标签:
这题有个巨坑的地方,棋子在第1行,每k列,行和列都是从0开始编号的!!!也就是实际是第2行,第k+1列!!!
看出来后就一大水题了。
经过转换可以使得每个棋子都只影响下一行,又由于列只有6,所以用状压解
f[i][[j]表示每i行状态为j的方案,然后我们发现每2行之间的转移是一样的,所以可以预处理转移矩阵,再矩乘加快速幂优化即可
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<cstring> #include<vector> using namespace std; typedef unsigned int ui; vector<int> lim[4]; struct Matrix{ ui a[65][65]; }pc,d; ui ans; ui f[1011]; int i,j,k,p,m,nj,l,n,L,sy; int a[4][10]; Matrix operator *(Matrix a,Matrix b) { Matrix c; memset(c.a,0,sizeof(c.a)); int i,j,k; for(i=0;i<(1<<m);i++) for(k=0;k<(1<<m);k++)if(a.a[i][k]){ for(j=0;j<(1<<m);j++)c.a[i][j]+=a.a[i][k]*b.a[k][j]; } return c; } Matrix mi(Matrix a,int z) { Matrix l; bool pz; int i,j; pz=true; while(z){ if(z%2==1){ if(pz){ pz=false; for(i=0;i<(1<<m);i++) for(j=0;j<(1<<m);j++)l.a[i][j]=a.a[i][j]; } else l=l*a; } a=a*a; z/=2; } return l; } bool check(int ls,int ts) { int i,j,sy,k; for(i=0;i<m;i++)if((ls&(1<<i))){ for(j=0;j<lim[3].size();j++){ k=lim[3][j]; sy=i+1+k-L; if(sy>0&&sy<=m){ if((ts&(1<<(sy-1))))return false; } } } for(i=0;i<m;i++)if((ts&(1<<i))){ for(j=0;j<lim[2].size();j++){ k=lim[2][j]; sy=i+1+k-L; if(sy>0&&sy<=m){ if(sy!=i+1&&(ts&(1<<(sy-1))))return false; } } } return true; } int main() { scanf("%d%d",&n,&m); scanf("%d%d",&p,&L); L++; for(i=1;i<=3;i++) for(j=1;j<=p;j++){ scanf("%d",&a[i][j]); if(a[2][j])lim[2].push_back(j); if(a[3][j])lim[3].push_back(j); } for(i=1;i<=p;i++)if(a[1][i]){ sy=L+L-i; lim[3].push_back(sy); } for(i=0;i<(1<<m);i++) for(j=0;j<(1<<m);j++)if(check(i,j))pc.a[i][j]=1; d=mi(pc,n); for(i=0;i<(1<<m);i++)if(pc.a[0][i])f[i]++; for(i=0;i<(1<<m);i++)ans+=f[i]*d.a[i][0]; printf("%u\n",ans); }
标签:
原文地址:http://www.cnblogs.com/applejxt/p/4475539.html