题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3256
题意:给一个n*m的棋盘,求从左上到左下的经过所有格子的方案数
在左边加一列问题就变成了求回路
由于m很大,所以我们需要按列dp
构造出矩阵后,用矩阵快速幂加速
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<stack> #include<map> #include<set> using namespace std; typedef long long ll; const int mod=7777777; const int HASH=419; const int STATE=1010; int n,m,D; int code[10],ch[10]; struct p { int a[200][200]; p(){memset(a,0,sizeof(a));} p operator *(const p&t) { p ans; for(int i=0;i<D;i++) for(int j=0;j<D;j++) { ll tem=0; for(int k=0;k<D;k++) tem+=1LL*a[i][k]*t.a[k][j]; ans.a[i][j]=tem%mod; } return ans; } }; p g; p qpow(p x,int m) { p ans; for(int i=0;i<D;i++) ans.a[i][i]=1; while(m) { if (m&1) ans=ans*x; x=x*x; m>>=1; } return ans; } struct hashmap { int head[HASH],nextt[STATE],sz; int state[STATE]; void init() { sz=0; memset(head,-1,sizeof(head)); } int push(int st) { int h=st%HASH; for(int i=head[h];i!=-1;i=nextt[i]) if (state[i]==st) return i; state[sz]=st; nextt[sz]=head[h]; head[h]=sz++; return sz-1; } }hm; void decode(int st) { for(int i=n-1;i>=0;i--) { code[i]=st&3; st>>=2; } } int encode() { int cnt=1,st=0; memset(ch,-1,sizeof(ch)); ch[0]=0; for(int i=0;i<n;i++) { if (ch[code[i]]==-1) ch[code[i]]=cnt++; st<<=2; st|=ch[code[i]]; } return st; } bool check(int st,int nst) { decode(st); int flag=0;//当前格子是否有上插头 int k,cnt=0; for(int i=0;i<n;i++) { if (flag==0)//没有 { if (!code[i]&&!(nst>>i&1)) return false;//没有左右插头 if (code[i]&&nst>>i&1) continue;//有左右插头 if (code[i]) flag=code[i];//插头从左边来,向下延伸 else flag=-1;//插头从下面来,向右延伸 k=i; } else { if (code[i]&&nst>>i&1) return false;//有上左右插头 if (!code[i]&&!(nst>>i&1)) continue;//没有左右插头,向下延伸 if (code[i])//有左插头 { if (code[i]==flag&&(i!=n-1||nst!=0)) return false;//如果不是最后一个格子,不能合并相同的插头 if (flag>0)//合并插头 { for(int j=0;j<n;j++) if (code[j]==code[i]&&j!=i) code[j]=code[k]; code[i]=code[k]=0; } else//向右延伸 { code[k]=code[i]; code[i]=0; } } else { if (flag>0)//向右延伸 { code[i]=code[k]; code[k]=0; } else//建立新的连通块 { code[i]=code[k]=n+cnt; cnt++; } } flag=0; } } if (flag!=0) return false; return true; } void init()//构造矩阵 { hm.init(); memset(code,0,sizeof(code)); code[0]=code[n-1]=1; hm.push(0); hm.push(encode()); memset(g.a,0,sizeof(g.a)); for(int i=1;i<hm.sz;i++) { int st=hm.state[i]; for(int nst=0;nst<1<<n;nst++) if (check(st,nst)) { int j=hm.push(encode()); g.a[i][j]=1; } } D=hm.sz; } void solve() { p ans=qpow(g,m); if (ans.a[1][0]==0) printf("Impossible "); else printf("%d ",ans.a[1][0]); } int main() { while(scanf("%d%d",&n,&m)!=EOF) { init(); solve(); } return 0; }