Luogu3977 [TJOI2015]棋盘

Description

link

给定一个大小为 \(n \times m\) 的棋盘,同时给定一个棋子的攻击范围的情况,是一个 \(3 \times p\) 的矩阵

要求放置棋子的方案数

\(p \le m ,n\le 10^6,m\le 6\)

Solution

这真的是阅读理解题,请仔细分析 \(0/1\) 后判断每个棋子的攻击范围

然后状压这部分就是一个考验代码能力的部分……(比如我写了俩小时,旁边的 \(@happyguy\) 就写了半小时……)

然后这样并不能通过本题,毕竟复杂度在那里……

然后我们发现这个转移是有向的……(这部分抄了题解……毕竟不会矩阵加速)

两个状态之间就是两个状态之间的指向性转移

然后建立初始矩阵,快速幂

Code

#include<bits/stdc++.h>
using namespace std;
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int N=1e6+10;
	bool vis[4][10],abl[100],t1[100][100],t2[100][100];
	int n,m,k,p,s;
	#define ui unsigned int
	struct node{
		ui a[100][100];
		ui* operator[](int x){return a[x];}
		inline void init(){memset(a,0,sizeof(a)); return ;}
		inline void work(){for(int i=0;i<=s;++i) a[i][i]=1; return ;}
	}b,a;
	inline node mul(node a,node b)
	{
		node res; res.init();
		for(int i=0;i<=s;++i)
		{
			for(int j=0;j<=s;++j)
			{
				for(int k=0;k<=s;++k) res[i][j]+=a[i][k]*b[k][j];
			}
		}
		return res;
	}
	inline bool judge1(int x,int y)
	{
		if(!abl[x]||!abl[y]) return 0;
		for(int i=1;i<=m;++i)
		{
			if(!(x&(1<<(i-1)))) continue;
			int t=i-k;
			for(int j=1;j<=m;++j)
			{
				if(j+t<1) continue;
				if(j+t>m) continue;
				if(!vis[3][j]) continue;
				if(y&(1<<(j+t-1))) return 0;
			}
		}
		return 1;
	}
	inline bool judge2(int x,int y)
	{
		if(!abl[x]||!abl[y]) return 0;
		for(int i=1;i<=m;++i)
		{
			if(!(x&(1<<(i-1)))) continue;
			int t=i-k;
			for(int j=1;j<=m;++j)
			{
				if(j+t<1) continue;
				if(j+t>m) continue;
				if(!vis[1][j]) continue;
				if(y&(1<<(j+t-1))) return 0;
			}
		}
		return 1;
	}
	inline bool c1(int x)
	{
		for(int i=1;i<=m;++i)
		{
			if(!(x&(1<<(i-1)))) continue;
			int t=i-k;
			for(int j=1;j<=p;++j)
			{
				if(!vis[2][j]) continue;
				if(j+t<1) continue;
				if(j+t>m) continue;
				if(x&(1<<(j+t-1))) return 0;
			} 
		} return 1;
	}
	signed main()
	{	
		n=read(); m=read(); p=read(); k=read()+1;
		for(int i=1;i<=3;++i)
		{
			for(int j=1;j<=p;++j) vis[i][j]=read();
		} vis[2][k]=0;
		s=(1<<m)-1;
		for(int i=0;i<=s;++i) abl[i]=c1(i);
		
		
		for(int i=0;i<=s;++i)
		{
			for(int j=0;j<=s;++j) t1[i][j]=judge1(i,j);
		}
	
		for(int i=0;i<=s;++i) 
		{
			for(int j=0;j<=s;++j) t2[i][j]=judge2(i,j);
		}
		for(int j=0;j<=s;++j)
		{
			for(int k=0;k<=s;++k)
			{
				if(t1[j][k]&&t2[k][j]) b[j][k]++;
			}
		}
		a=b; --n; for(;n;n>>=1,a=mul(a,a)) if(n&1) b=mul(b,a);
		ui ans=0; for(int i=0;i<=s;++i) ans+=b[n][i]; cout<<ans<<endl;
  		return 0;
	}
}
signed main(){return yspm::main();}

猜你喜欢

转载自www.cnblogs.com/yspm/p/13406623.html