1. 程式人生 > 實用技巧 >Luogu3977 [TJOI2015]棋盤

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();}