BZOJ1126: [POI2008]Uci
$n \leq 100,m \leq 100$,$n*m$的01矩形,问从左下角开始往上走,每次转弯只能向右,不能经过重复点,不能撞到1,到达点$(x,y)$的方案数,$mod \ \ k$。
感人肺腑的细节题写了一天。。
可以发现他在做一个绕圈运动,运动的过程中逐渐限制自己的活动范围,因此可以用活动范围和射入方向表示状态(这样也就确定了它的位置),$f[L][R][U][D][0123]$--沿左边向上、沿上边向右、沿右边向下、沿下边向左射入矩形$[L,R,U,D]$的方案。如图:
这样转移可以用一个前缀和转移。比如上转右的:
用纵方向一个前缀的蓝色矩形转移到右方向的一个矩形。这样就可以$O(1)$转移了。
由于四维开不下,要把L那一维滚动掉,所以记前缀和的时候,左转上那个数组不要清,那里实际保留了所有$L_2<L$转移到$L$的状态的前缀和。
记答案的时候,在目标处转弯时记录答案。注意最后一圈不要记重了。这句话是啥意思我也说不清,看代码吧QAQ
1 //#include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 //#include<time.h> 6 //#include<complex> 7 #include<algorithm> 8 #include<stdlib.h> 9 using namespace std; 10 11 int n,m,mod,tx,ty; 12 #define maxn 111 13 int f[2][maxn][maxn][maxn][4],cur,sum[maxn][maxn][maxn][4],bl[maxn][maxn][4]; char s[maxn]; 14 bool mp[maxn][maxn]; //0 up 1 right 2 down 3 left 15 int main() 16 { 17 scanf("%d%d%d%d%d",&n,&m,&mod,&ty,&tx); 18 for (int i=1;i<=n;i++) 19 { 20 scanf("%s",s+1); 21 for (int j=1;j<=m;j++) mp[i][j]=(s[j]=='+'); 22 } 23 24 for (int j=1;j<=m;j++) 25 { 26 bl[0][j][0]=0; 27 for (int i=1;i<=n;i++) if (mp[i][j]) bl[i][j][0]=bl[i-1][j][0]; 28 else bl[i][j][0]=i; 29 } 30 for (int i=1;i<=n;i++) 31 { 32 bl[i][m+1][1]=m+1; 33 for (int j=m;j;j--) if (mp[i][j]) bl[i][j][1]=bl[i][j+1][1]; 34 else bl[i][j][1]=j; 35 } 36 for (int j=1;j<=m;j++) 37 { 38 bl[n+1][j][2]=n+1; 39 for (int i=n;i;i--) if (mp[i][j]) bl[i][j][2]=bl[i+1][j][2]; 40 else bl[i][j][2]=i; 41 } 42 for (int i=1;i<=n;i++) 43 { 44 bl[i][0][3]=0; 45 for (int j=1;j<=m;j++) if (mp[i][j]) bl[i][j][3]=bl[i][j-1][3]; 46 else bl[i][j][3]=j; 47 } 48 cur=0; for (int i=1;i<=n;i++) sum[m][i][n][0]=1; 49 50 int ans=0; 51 for (int L=2;L<=ty+1;L++) 52 { 53 cur^=1; 54 for (int R=m;R>=ty;R--) for (int U=1;U<=tx;U++) for (int D=max(U,tx);D<=n;D++) 55 { 56 sum[R][U][D][1]=sum[R+1][U][D][1]; 57 f[cur][R][U][D][1]=0; 58 if (bl[D][L-1][0]<U) 59 { 60 f[cur][R][U][D][1]=sum[R][U][D][0]; 61 sum[R][U][D][1]+=f[cur][R][U][D][1]; sum[R][U][D][1]-=sum[R][U][D][1]>=mod?mod:0; 62 } 63 if (L-1==ty && U==tx) ans+=f[cur][R][U][D][1],ans-=ans>=mod?mod:0; 64 } 65 if (L==ty+1) break; 66 for (int D=n;D>=tx;D--) for (int R=ty;R<=m;R++) for (int U=2;U<=tx+1;U++) 67 { 68 sum[R][U][D][2]=sum[R][U][D+1][2]; 69 f[cur][R][U][D][2]=0; 70 if (bl[U-1][L-1][1]>R) 71 { 72 f[cur][R][U][D][2]=sum[R][U-1][D][1]; 73 sum[R][U][D][2]+=f[cur][R][U][D][2]; sum[R][U][D][2]-=sum[R][U][D][2]>=mod?mod:0; 74 } 75 if (U-1==tx && R==ty) ans+=f[cur][R][U][D][2],ans-=ans>=mod?mod:0; 76 } 77 for (int D=n;D>=tx;D--) for (int R=ty;R<=m;R++) sum[R][1][D][2]=sum[R][1][D+1][2]; 78 for (int U=1;U<=tx;U++) for (int D=max(tx,U);D<=n;D++) for (int R=ty-1;R<m;R++) 79 { 80 f[cur][R][U][D][3]=0; 81 if (bl[U][R+1][2]>D) 82 { 83 f[cur][R][U][D][3]=sum[R+1][U][D][2]; 84 sum[R][U][D][3]+=f[cur][R][U][D][3]; sum[R][U][D][3]-=sum[R][U][D][3]>=mod?mod:0; 85 } 86 if (D==tx && R+1==ty) ans+=f[cur][R][U][D][3],ans-=ans>=mod?mod:0; 87 } 88 for (int U=1;U<=tx;U++) for (int D=tx-1;D<=n;D++) for (int R=ty;R<=m;R++) 89 { 90 if (U) sum[R][U][D][0]=sum[R][U-1][D][0]; 91 f[cur][R][U][D][0]=0; 92 if (bl[D+1][R][3]<L) 93 { 94 f[cur][R][U][D][0]=sum[R][U][D+1][3]; 95 sum[R][U][D][0]+=f[cur][R][U][D][0]; sum[R][U][D][0]-=sum[R][U][D][0]>=mod?mod:0; 96 } 97 if (D+1==tx && L==ty) ans+=f[cur][R][U][D][0],ans-=ans>=mod?mod:0; 98 } 99 for (int U=1;U<=tx;U++) for (int R=ty;R<=m;R++) sum[R][U][n][0]=sum[R][U-1][n][0]; 100 } 101 printf("%d\n",ans); 102 return 0; 103 }