[ZOJ3256] Tour in the Castle

  插头DP+矩阵乘法

  m喜闻乐见地达到了10^9级别。。而n<=7,并且没有障碍。。所以列与列之间的转移时一样的。。就可以上矩乘了。

  感觉自己快没救了。。看半天题解还是不懂。。

  http://www.cnblogs.com/staginner/archive/2012/09/14/2684712.html 题解其实讲的很清楚了。。

  在枚举转移的状态的时候想乱了好几次。。2^n枚举的是有没有右插头,处理新出现路径的姿势也和平时不同。。。

  剩下的就是矩乘了。。

 #include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
const int maxzt=,modd=;
struct zs1{
int last[],tot;
inline int get(int x){
if(last[x])return last[x];
last[x]=++tot,zt[tot]=x;
return tot;
}
int zt[];
}hm;
int mp[];
int a[][],c[][],b[][],map[][][];
int len[];
int i,j,k,n,m,l; inline void decode(int x){
for(int i=n;i>=;i--)mp[i]=x&,x>>=;
}
bool u[];int id[];
inline int encode(){
int i,x=,cnt=;
memset(u,,);
for(i=;i<=n;mp[i]=id[mp[i]],x=x<<|mp[i],i++)
if(!u[mp[i]]&&mp[i]>)u[mp[i]]=,id[mp[i]]=++cnt;
return x;
} inline bool check(int prezt,int nowzt){
int i,up=,left,pre=,sm=n-;bool r;
decode(prezt);
// for(i=1;i<=n;i++)printf(" %d",mp[i]);printf(" %d\n",prezt);
for(i=;i<=n;i++){
r=(nowzt&(<<(i-)))>,left=mp[i];
// printf(" up:%d r:%d l:%d\n",up,r,left);
if((up&&r&&left)||(!up&&!r&&!left))return ;
if(!up){
if(left&&r)continue;
pre=i;
if(!r)up=mp[i];
if(!left)up=-;
}else{
if(left){
if(left==up&&(i<n||nowzt!=))return ;
if(up>){
mp[pre]=mp[i]=;
for(int j=;j<=n;j++)if(mp[j]==left)mp[j]=up;
}else mp[pre]=mp[i],mp[i]=;
}
if(r){
if(up>)mp[i]=up,mp[pre]=;
else mp[i]=mp[pre]=++sm;
}
if(left||r)up=;
}
}
return up==;
}
inline void prerun(){
int i,j,k;
hm.tot=;memset(hm.last,,sizeof(hm.last));
memset(mp,,sizeof(mp));
hm.get(),
mp[]=mp[n]=,hm.get(encode());//printf(" %d\n",encode());
for(i=;i<=hm.tot;i++){//printf(" %d\n",n) ;
int zt=hm.zt[i];decode(zt);
// for(j=1;j<=n;j++)printf(" %d",mp[j]);puts("");
for(j=;j<(<<n);j++)if(check(zt,j))
k=hm.get(encode()),
map[n][i][k]=;//,printf(" %d %d\n",j,k);
}
len[n]=hm.tot;
}
inline void multoa(){
int i;register int j,k;ll tmp;
for(i=;i<=l;i++)for(j=;j<=l;b[i][j]=tmp%modd,j++)
for(tmp=,k=;k<=l;k++)tmp+=(ll)a[i][k]*a[k][j];
for(i=;i<=l;i++)for(j=;j<=l;j++)a[i][j]=b[i][j];
}
inline void multoc(){
int i;register int j,k;ll tmp;
for(i=;i<=l;i++)for(j=;j<=l;b[i][j]=tmp%modd,j++)
for(tmp=,k=;k<=l;k++)tmp+=(ll)a[i][k]*c[k][j];
for(i=;i<=l;i++)for(j=;j<=l;j++)c[i][j]=b[i][j];
}
int main(){
for(i=;i<=;i++)n=i,prerun();//return 233;
while(scanf("%d",&n)!=EOF){
scanf("%d",&m);
if(n==&&m==){
puts("");continue;
}
if((n&)&&!(m&)){
puts("Impossible");continue;
}
memcpy(a,map[n],sizeof(map[n]));l=len[n];
memset(c,,sizeof(c));
for(i=;i<=l;i++)c[i][i]=;
while(m){
if(m&)multoc();
m>>=;if(m)multoa();
}
if(!c[][])puts("Impossible");else printf("%d\n",c[][]);//return 233;
}
return ;
}

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

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

[ZOJ3256] Tour in the Castle

上一篇:Java程序国际化学习代码一


下一篇:自学Python4.9-生成器举例