After the final BOSS is defeated, the hero found that the whole castle is collapsing (very familiar scene, isn't it). Escape from the castle is easy, just need to cross a few rooms. But as the Hero is full of adventurous spirit, he decides to visit every room before he escape the castle.
The castle is a rectangle with N * M rooms in it. Two rooms are connected if they share a common edge. The hero starts in the top left room. And the bottom left room is the only way out. After the hero visits a room and leaves it, it will collapse immediately(Another familiar scene). So he can visit each room only once.
The diagram shows one tour over a castle with 4 * 10 rooms:
Input
There are multiply cases (<20), process to the end of file.
Each case contains a line with two Integer N and M (2 <= N <= 7, 1 <= M <=10^9).
Ouput
For each case, if it's impossible to visit every room exactly once and get to the bottom left room, output "Impossible". Otherwise, output the number of tours as it describe above. Beacause the answer can be huge, you just need to output the answer MOD 7777777.
Sample Input
3 2 3 3 4 10
Sample Output
Impossible 2 2329
解题报告:那个M的取值很夸张。不过第一意识还是想到了二分快速幂。至于怎么建立模型,构造矩阵,倒是想了挺久。
我们可以先枚举所有可能的状态,以此状态为一行的初状态,用插头DP的方式计算所有可能的一行后的状态及其数量,以此构造矩阵。
最后一行单独处理。代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int maxn=1117; const int MOD=7777777; const int L=2;// 4进制 int now,pre; int n,m; int size; struct Node { int H[maxn]; int S[maxn]; int N[maxn]; int size; void init() { size=0; memset(H,-1,sizeof(H)); } void push(int SS,int num) { int s=SS%maxn; while( ~H[s] && S[H[s]]!=SS ) s=(s+1)%maxn; if( ~H[s] ) { N[H[s]]=(N[H[s]]+num)%MOD; return; } S[size]=SS; N[size]=num%MOD; H[s]=size++; } int get(int SS) { int s=SS%maxn; while( ~H[s] && S[H[s]]!=SS ) s=(s+1)%maxn; if( ~H[s] ) return N[H[s]]; return 0; } int getIndex(int SS) { int s=SS%maxn; while( ~H[s] && S[H[s]]!=SS ) s=(s+1)%maxn; if( ~H[s] ) return H[s]; return -1; } } dp[3]; int get(int S,int p) { return (S>>(p*L))&((1<<L)-1); } void set(int &S,int p,int v) { S^=get(S,p)<<(p*L); S^=v<<(p*L); } struct Martrix { int a[128][128]; Martrix() { memset(a,0,sizeof(a)); } Martrix operator*(const Martrix& cmp) const { Martrix c; for(int i=0;i<size;i++) for(int j=0;j<size;j++) for(int k=0;k<size;k++) // 矩阵内部乘法越界问题 c.a[i][j]=(c.a[i][j]+(int)(((LL)a[i][k]*cmp.a[k][j])%MOD))%MOD; return c; } }; void init() { dp[2].init(); int total=(1<<(n*2)); for(int S=0;S<total;S++) { int v; int one=0,two=0; for(int j=0;j<n;j++) { v=get(S,j); if(v==3) break; if(v==2) two++; if(v==1) one++; if(two>one) break; } if(v==3) continue; if(one!=two) continue; dp[2].push(S<<L,1); } size=dp[2].size; } int line(int SS,int nn) { now=1; pre=0; int ans=0; dp[now].init(); dp[now].push(SS,nn); for(int j=0;j<n;j++) { swap(now,pre); dp[now].init(); for(int s=0;s<dp[pre].size;s++) { int S=dp[pre].S[s]; int num=dp[pre].N[s]; int p=get(S,j); int q=get(S,j+1); if(p==0 && q==0) { if(j<n-1) { set(S,j,1); set(S,j+1,2); dp[now].push(S,num); } } else if((p>0)^(q>0)) { if(j+(q>0)<n) dp[now].push(S,num); set(S,j,q); set(S,j+1,p); if(j+(p>0)<n) dp[now].push(S,num); } else if(p==1 && q==2) { set(S,j,0); set(S,j+1,0); if(j==n-1 && S==0) ans=(ans+num)%MOD; } else if(p==2 && q==1) { set(S,j,0); set(S,j+1,0); dp[now].push(S,num); } else if(p==1 && q==1) { int find=1; for(int k=j+2;k<=n;k++) { int v=get(S,k); if(v==1) find++; else if(v==2) find--; if(find==0) { set(S,j,0); set(S,j+1,0); set(S,k,1); dp[now].push(S,num); break; } } } else if(p==2 && q==2) { int find=1; for(int k=j-1;k>=0;k--) { int v=get(S,k); if(v==2) find++; else if(v==1) find--; if(find==0) { set(S,j,0); set(S,j+1,0); set(S,k,2); dp[now].push(S,num); break; } } } } } for(int s=0;s<dp[now].size;s++) dp[now].S[s]<<=L; return ans; } void quick(Martrix& a,int num) { Martrix res=a; num--; while(num) { if(num&1) res=a*res; a=a*a; num>>=1; } a=res; } int main() { while(~scanf("%d%d",&n,&m)) { if(m==1) {puts("1");continue;} if(n%2 && m%2==0) {puts("Impossible");continue;} init(); Martrix a; for(int i=0;i<size;i++) { line(dp[2].S[i],1); for(int s=0;s<dp[now].size;s++) a.a[i][dp[2].getIndex(dp[now].S[s])]=dp[now].N[s]; } quick(a,m-1); int STA=0; set(STA,1,1); set(STA,n,2); int no=dp[2].getIndex(STA); int ans=0; bool success=false; for(int i=0;i<size;i++) { ans+=line(dp[2].S[i],a.a[no][i]); if(ans) success=true; ans%=MOD; } if(success) printf("%d\n",ans); else puts("Impossible"); } }