[ZOJ3256] Tour in the Castle

  插头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
",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
",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
",encode());
 69     for(i=2;i<=hm.tot;i++){//printf("   %d
",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
",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
",c[2][1]);//return 233;
108     }
109     return 0;
110 }
View Code

发现我的矩乘比标程的慢了不少。。QAQ

本来要跑150ms的。。然后顺手加了对极限数据、无解的特判。。然后直接0ms吓哭...数据竟然这么水= =

原文地址:https://www.cnblogs.com/czllgzmzl/p/5494340.html