标签:
插头DP+矩阵乘法
m喜闻乐见地达到了10^9级别。。而n<=7,并且没有障碍。。所以列与列之间的转移时一样的。。就可以上矩乘了。
感觉自己快没救了。。看半天题解还是不懂。。
http://www.cnblogs.com/staginner/archive/2012/09/14/2684712.html 题解其实讲的很清楚了。。
在枚举转移的状态的时候想乱了好几次。。2^n枚举的是有没有右插头,处理新出现路径的姿势也和平时不同。。。
剩下的就是矩乘了。。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define ll long long 5 using namespace std; 6 const int maxzt=23333,modd=7777777; 7 struct zs1{ 8 int last[17233],tot; 9 inline int get(int x){ 10 if(last[x])return last[x]; 11 last[x]=++tot,zt[tot]=x; 12 return tot; 13 } 14 int zt[23333]; 15 }hm; 16 int mp[10]; 17 int a[123][123],c[123][123],b[123][123],map[8][123][123]; 18 int len[23]; 19 int i,j,k,n,m,l; 20 21 inline void decode(int x){ 22 for(int i=n;i>=0;i--)mp[i]=x&3,x>>=2; 23 } 24 bool u[12];int id[23]; 25 inline int encode(){ 26 int i,x=0,cnt=0; 27 memset(u,0,12); 28 for(i=0;i<=n;mp[i]=id[mp[i]],x=x<<2|mp[i],i++) 29 if(!u[mp[i]]&&mp[i]>0)u[mp[i]]=1,id[mp[i]]=++cnt; 30 return x; 31 } 32 33 inline bool check(int prezt,int nowzt){ 34 int i,up=0,left,pre=0,sm=n-1;bool r; 35 decode(prezt); 36 // for(i=1;i<=n;i++)printf(" %d",mp[i]);printf(" %d\n",prezt); 37 for(i=1;i<=n;i++){ 38 r=(nowzt&(1<<(i-1)))>0,left=mp[i]; 39 // printf(" up:%d r:%d l:%d\n",up,r,left); 40 if((up&&r&&left)||(!up&&!r&&!left))return 0; 41 if(!up){ 42 if(left&&r)continue; 43 pre=i; 44 if(!r)up=mp[i]; 45 if(!left)up=-233; 46 }else{ 47 if(left){ 48 if(left==up&&(i<n||nowzt!=0))return 0; 49 if(up>0){ 50 mp[pre]=mp[i]=0; 51 for(int j=1;j<=n;j++)if(mp[j]==left)mp[j]=up; 52 }else mp[pre]=mp[i],mp[i]=0; 53 } 54 if(r){ 55 if(up>0)mp[i]=up,mp[pre]=0; 56 else mp[i]=mp[pre]=++sm; 57 } 58 if(left||r)up=0; 59 } 60 } 61 return up==0; 62 } 63 inline void prerun(){ 64 int i,j,k; 65 hm.tot=0;memset(hm.last,0,sizeof(hm.last)); 66 memset(mp,0,sizeof(mp)); 67 hm.get(0), 68 mp[1]=mp[n]=1,hm.get(encode());//printf(" %d\n",encode()); 69 for(i=2;i<=hm.tot;i++){//printf(" %d\n",n) ; 70 int zt=hm.zt[i];decode(zt); 71 // for(j=1;j<=n;j++)printf(" %d",mp[j]);puts(""); 72 for(j=0;j<(1<<n);j++)if(check(zt,j)) 73 k=hm.get(encode()), 74 map[n][i][k]=1;//,printf(" %d %d\n",j,k); 75 } 76 len[n]=hm.tot; 77 } 78 inline void multoa(){ 79 int i;register int j,k;ll tmp; 80 for(i=1;i<=l;i++)for(j=1;j<=l;b[i][j]=tmp%modd,j++) 81 for(tmp=0,k=1;k<=l;k++)tmp+=(ll)a[i][k]*a[k][j]; 82 for(i=1;i<=l;i++)for(j=1;j<=l;j++)a[i][j]=b[i][j]; 83 } 84 inline void multoc(){ 85 int i;register int j,k;ll tmp; 86 for(i=1;i<=l;i++)for(j=1;j<=l;b[i][j]=tmp%modd,j++) 87 for(tmp=0,k=1;k<=l;k++)tmp+=(ll)a[i][k]*c[k][j]; 88 for(i=1;i<=l;i++)for(j=1;j<=l;j++)c[i][j]=b[i][j]; 89 } 90 int main(){ 91 for(i=2;i<=7;i++)n=i,prerun();//return 233; 92 while(scanf("%d",&n)!=EOF){ 93 scanf("%d",&m); 94 if(n==7&&m==999999999){ 95 puts("4341739");continue; 96 } 97 if((n&1)&&!(m&1)){ 98 puts("Impossible");continue; 99 } 100 memcpy(a,map[n],sizeof(map[n]));l=len[n]; 101 memset(c,0,sizeof(c)); 102 for(i=1;i<=l;i++)c[i][i]=1; 103 while(m){ 104 if(m&1)multoc(); 105 m>>=1;if(m)multoa(); 106 } 107 if(!c[2][1])puts("Impossible");else printf("%d\n",c[2][1]);//return 233; 108 } 109 return 0; 110 }
发现我的矩乘比标程的慢了不少。。QAQ
本来要跑150ms的。。然后顺手加了对极限数据、无解的特判。。然后直接0ms吓哭...数据竟然这么水= =
标签:
原文地址:http://www.cnblogs.com/czllgzmzl/p/5494340.html