【BZOJ】2331: [SCOI2011]地板
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2331
一眼插头DP...
考虑一个L形的东西,要构成它可以划分为两个阶段,即当前线段是拐了弯的还是没有拐弯的。
所以$4$进制表示,$0$表示没有插头,$1$表示插头指向拐点,$2$表示插头离开拐点。
转移:
令${(x,y)}$表示当前点左插头和上插头的形态。
${(0,0)}$------>${(0,1)}$,${(1,0)}$,${(2,2)}$
${(0,1)}$------>${(1,0)}$,${(0,2)}$
${(0,2)}$------>${(0,0)}$,${(2,0)}$
${(1,0)}$------>${(0,1)}$,${(2,0)}$
${(2,0)}$------>${(0,0)}$,${(0,2)}$
当然如果有障碍就不能走。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstdlib> 6 #include<cmath> 7 #include<cstring> 8 using namespace std; 9 #define maxn 10010 10 #define llg long long 11 #define SIZE 10007 12 #define md 20110520 13 #define maxnZT (1<<21) 14 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); 15 llg n,m,code[maxn],zt[2][maxnZT],v[2][maxnZT],g[110][110],size[2],now,la; 16 17 struct node 18 { 19 llg pos,x,val; 20 }; 21 22 vector<node>a[2][SIZE]; 23 24 void outcode(llg x){for (llg i=0;i<=m;i++) code[i]=x&3,x>>=2;} 25 26 void encode(llg p,llg val) 27 { 28 llg x=0; 29 for (llg i=0;i<=m;i++) x+=code[i]*(1<<(i*2)); 30 llg wz=x%SIZE,E=a[p][wz].size(); 31 for (llg i=0;i<E;i++) 32 if (a[p][wz][i].x==x) 33 { 34 a[p][wz][i].val+=val; a[p][wz][i].val%=md; 35 v[p][a[p][wz][i].pos]+=val; v[p][a[p][wz][i].pos]%=md; 36 return ; 37 } 38 size[p]++; 39 node NEW; 40 NEW.pos=size[p],NEW.x=x,NEW.val=val; 41 a[p][wz].push_back(NEW); 42 zt[p][size[p]]=x; v[p][size[p]]=val; 43 } 44 45 void init() 46 { 47 cin>>n>>m; 48 char ch; 49 for (llg i=1;i<=n;i++) 50 for (llg j=1;j<=m;j++) 51 { 52 ch=getchar(); 53 while (ch!='*' && ch!='_') ch=getchar(); 54 if (n<m) g[j][i]=(ch=='_'); 55 else g[i][j]=(ch=='_'); 56 } 57 if (n<m) swap(n,m); 58 } 59 60 void init_a(llg p){for (llg i=0;i<SIZE;i++) a[p][i].clear(); size[p]=0;} 61 62 void DP() 63 { 64 llg le,up,V; 65 encode(0,1); 66 for (llg i=1;i<=n;i++) 67 { 68 for (llg k=1;k<=size[now];k++) zt[now][k]*=4;//轮廓线左移一格 69 for (llg j=1;j<=m;j++) 70 { 71 now^=1; la=now^1; size[now]=0; 72 init_a(now); 73 for (llg k=1;k<=size[la];k++) 74 { 75 outcode(zt[la][k]); 76 le=code[j-1],up=code[j],V=v[la][k];//提取左插头和上插头 77 78 if (g[i][j]==0) 79 { 80 if (le==0 && up==0) encode(now,V); 81 continue; 82 } 83 84 if (!le && !up) 85 { 86 if (j<m && g[i][j+1]==1) 87 { 88 code[j-1]=0,code[j]=1; 89 encode(now,V); 90 if (g[i+1][j]==1) 91 { 92 code[j-1]=code[j]=2; 93 encode(now,V); 94 } 95 } 96 if (g[i+1][j]==1) 97 { 98 code[j-1]=1,code[j]=0; 99 encode(now,V); 100 } 101 continue; 102 } 103 104 if (le && up) 105 { 106 if (le==1 && up==1) 107 { 108 code[j-1]=code[j]=0; 109 encode(now,V); 110 } 111 continue; 112 } 113 114 if (le==1 && up==0) 115 { 116 if (g[i+1][j]==1) 117 { 118 code[j-1]=2; 119 encode(now,V); 120 } 121 if (g[i][j+1]==1 && j<m) 122 { 123 code[j]=1; code[j-1]=0; 124 encode(now,V); 125 } 126 continue; 127 } 128 129 if (le==2 && up==0) 130 { 131 if (j<m && g[i][j+1]==1) 132 { 133 code[j]=2; code[j-1]=0; 134 encode(now,V); 135 } 136 code[j]=code[j-1]=0; 137 encode(now,V); 138 continue; 139 } 140 141 if (le==0 && up==1) 142 { 143 if (g[i+1][j]==1) 144 { 145 code[j-1]=1,code[j]=0; 146 encode(now,V); 147 } 148 if (j<m && g[i][j+1]==1) 149 { 150 code[j-1]=0; code[j]=2; 151 encode(now,V); 152 } 153 continue; 154 } 155 156 if (le==0 && up==2) 157 { 158 if (g[i+1][j]==1) 159 { 160 code[j]=0,code[j-1]=2; 161 encode(now,V); 162 } 163 code[j-1]=code[j]=0; 164 encode(now,V); 165 continue; 166 } 167 } 168 } 169 } 170 } 171 172 int main() 173 { 174 yyj("BZOJ2331"); 175 init(); 176 DP(); 177 llg ans=0; 178 bool pd; 179 for (llg i=1;i<=size[now];i++) 180 { 181 outcode(zt[now][i]); 182 pd=true; 183 for (llg j=0;j<=m;j++) if (code[j]) pd=false; 184 if (pd) ans+=v[now][i]; 185 } 186 cout<<ans%md; 187 return 0; 188 }
本文作者:xrdog
作者博客:http://www.cnblogs.com/Dragon-Light/
转载请注明出处,侵权必究,保留最终解释权!