【BZOJ4000】[TJOI2015]棋盤(矩陣快速冪,動態規劃)
阿新 • • 發佈:2019-04-24
++ sig ostream amp mem sin 需要 || []
【BZOJ4000】[TJOI2015]棋盤(矩陣快速冪,動態規劃)
題面
BZOJ
洛谷
題解
發現所有的東西都是從\(0\)開始編號的,所以狀壓只需要壓一行就行了。
然後就可以隨意矩乘了。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define uint unsigned int inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } int n,m,P,k,N; struct Matrix { uint s[64][64]; void clear(){memset(s,0,sizeof(s));} void init(){clear();for(int i=0;i<N;++i)s[i][i]=1;} uint*operator[](int x){return s[x];} }T; Matrix operator*(Matrix a,Matrix b) { Matrix c;c.clear(); for(int i=0;i<N;++i) for(int j=0;j<N;++j) for(int k=0;k<N;++k) c[i][j]+=a[i][k]*b[k][j]; return c; } Matrix fpow(Matrix a,int b) { Matrix s;s.init(); while(b){if(b&1)s=s*a;a=a*a;b>>=1;} return s; } int lim[3],forbid[3][64],zt[64]; int main() { n=read();m=read();P=read();k=read(); for(int i=0;i<3;++i) for(int j=0;j<P;++j)lim[i]|=read()<<j; lim[1]^=1<<k;N=1<<m; for(int i=0;i<N;++i) for(int j=0;j<m;++j) if(i&(1<<j)) { forbid[0][i]|=(j<k)?lim[0]>>(k-j):lim[0]<<(j-k); forbid[1][i]|=(j<k)?lim[1]>>(k-j):lim[1]<<(j-k); forbid[2][i]|=(j<k)?lim[2]>>(k-j):lim[2]<<(j-k); } int tmp=0; for(int i=0;i<N;++i) if(!(i&forbid[1][i]))zt[tmp++]=i; N=tmp; for(int i=0;i<N;++i) for(int j=0;j<N;++j) if(((forbid[2][zt[i]]&zt[j])==0)&&((forbid[0][zt[j]]&zt[i])==0)) ++T[i][j]; T=fpow(T,n); uint ans=0; for(int i=0;i<N;++i)ans+=T[0][i]; printf("%u\n",ans); return 0; }
【BZOJ4000】[TJOI2015]棋盤(矩陣快速冪,動態規劃)