bzoj 2331: [SCOI2011]地板【插頭dp】
阿新 • • 發佈:2019-01-04
一開始設計了四種狀態,多了一種已經拐彎但是長度為0的情況,後來發現不用,設012表示沒插頭,沒拐彎的插頭,拐了彎的插頭,然後轉移的話12,21,22都不合法,剩下的轉移腦補一下即可,ans只能在11,02,20取,別的都不是合法結束狀態
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=105,mod=20110520,has=739391; int n,m,a[N][N],b[N],h[1000005],c[2],nw,la,tx,ty,ans; char s[N]; struct qwe { int ne,to[2],va[2]; }f[1000005]; void jia(int &x,int y) { x+=y; x>=mod?x-=mod:0; } void add(int x,int v) { int u=x%has+1; for(int i=h[u];i;i=f[i].ne) if(f[i].to[nw]==x) { jia(f[i].va[nw],v); return; } c[nw]++; f[c[nw]].ne=h[u]; f[c[nw]].to[nw]=x; f[c[nw]].va[nw]=v; h[u]=c[nw]; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%s",s+1); for(int j=1;j<=m;j++) if(s[j]=='_') { if(n>m) a[i][j]=1; else a[j][i]=1; } } if(n<m) swap(n,m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(a[i][j]) tx=i,ty=j; b[0]=1; for(int i=1;i<=20;i++) b[i]=(b[i-1]<<2); c[0]=1,f[1].va[0]=1,f[1].to[0]=0; for(int i=1;i<=n;i++) { for(int j=1;j<=c[nw];j++) f[j].to[nw]<<=2; for(int j=1;j<=m;j++) { memset(h,0,sizeof(h)); la=nw,nw^=1; c[nw]=0; for(int k=1;k<=c[la];k++) { int x=f[k].to[la],b1=(x>>(j*2-2))%4,b2=(x>>(j*2))%4,v=f[k].va[la]; if(!a[i][j]) { if(b1==0&&b2==0) add(x,v); } else if(b1==0&&b2==0) { if(a[i+1][j]&&a[i][j+1]) add(x+2*b[j-1]+2*b[j],v); if(a[i+1][j]) add(x+b[j-1],v); if(a[i][j+1]) add(x+b[j],v); } else if(b1==0&&b2==1) { if(a[i][j+1]) add(x+b[j],v); if(a[i+1][j]) add(x+b[j-1]-b[j],v); } else if(b1==0&&b2==2) { if(i==tx&&j==ty) jia(ans,v); add(x-2*b[j],v); if(a[i+1][j]) add(x+2*b[j-1]-2*b[j],v); } else if(b1==1&&b2==0) { if(a[i+1][j]) add(x+b[j-1],v); if(a[i][j+1]) add(x-b[j-1]+b[j],v); } else if(b1==1&&b2==1) { if(i==tx&&j==ty) jia(ans,v); add(x-b[j-1]-b[j],v); } else if(b1==2&&b2==0) { if(i==tx&&j==ty) jia(ans,v); add(x-2*b[j-1],v); if(a[i][j+1]) add(x-2*b[j-1]+2*b[j],v); } } } } printf("%d\n",ans); return 0; }