【bzoj2331】[SCOI2011]地板 插头dp

来源:互联网 发布:淘宝商城入驻费用 编辑:程序博客网 时间:2024/04/29 02:54
插头dp
f[i][j][S]表示转移到第i行第j列轮廓线为S的方案数
0表示没有插头,1表示插头没有拐过弯,2表示插头拐过弯
1、
3进制不好写,写4进制
一共3^11个状态,200000左右
bit[i]=i*2
取出4进制的第i位  (S/(1<<bit[i-1]))%4
状态的第j位  1<<bit[j-1]
2、
bfs只记录有用的状态
3、
因为f[i][j]只与f[i][j-1]有关,所以不妨用滚动数组
4、

有下插头的位置正下方必然有上插头


#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>#include<iostream>#define maxn 200010#define mod 20110520using namespace std;int a[110][110];int f[2][maxn],tot[2],hash[2][maxn],head[50010],to[maxn],next[maxn],bit[110];int n,m,now,pre,num;char s[110];void add(int s,int d){int x=s%50000;for (int p=head[x];p;p=next[p])  if (hash[now][to[p]]==s)  {  f[now][to[p]]=(f[now][to[p]]+d)%mod;  return;  }tot[now]++;hash[now][tot[now]]=s;f[now][tot[now]]=d;num++;to[num]=tot[now];next[num]=head[x];head[x]=num;}void dp(){now=1;pre=0;tot[now]=1;hash[now][1]=0;f[now][1]=1;for (int i=1;i<=n;i++){for (int j=1;j<=tot[now];j++) hash[now][j]<<=2;for (int j=1;j<=m;j++){swap(now,pre);tot[now]=0;num=0;memset(f[now],0,sizeof(f[now]));memset(head,0,sizeof(head));for (int k=1;k<=tot[pre];k++){int s=hash[pre][k],num=f[pre][k];if (!num) continue;int p=(s/(1<<bit[j-1]))%4,q=(s/(1<<bit[j]))%4;if (!a[i][j]){if (!p && !q) add(s,num);}else if (!p && !q){if (a[i+1][j]) add(s+(1<<bit[j-1]),num);if (a[i][j+1]) add(s+(1<<bit[j]),num);if (a[i+1][j] && a[i][j+1]) add(s+(1<<bit[j-1]+1)+(1<<(bit[j]+1)),num);}else if (!p){if (q==1){s-=(1<<bit[j]);if (a[i][j+1]) add(s+(1<<bit[j]+1),num);if (a[i+1][j]) add(s+(1<<bit[j-1]),num);}else{s-=(1<<bit[j]+1);add(s,num);if (a[i+1][j]) add(s+(1<<bit[j-1]+1),num);}}else if (!q){if (p==1){s-=(1<<bit[j-1]);if (a[i][j+1]) add(s+(1<<bit[j]),num);if (a[i+1][j]) add(s+(1<<bit[j-1]+1),num);}else{s-=(1<<bit[j-1]+1);add(s,num);if (a[i][j+1]) add(s+(1<<bit[j]+1),num);}}else if (p==1 && q==1){s-=(1<<bit[j-1])+(1<<bit[j]);add(s,num);}}}}}int main(){for (int i=0;i<=100;i++) bit[i]=i*2;scanf("%d%d",&n,&m);if (n>=m){for (int i=1;i<=n;i++){scanf("%s",s+1);for (int j=1;j<=m;j++)  if (s[j]=='_') a[i][j]=1; else a[i][j]=0;}}else{for (int i=1;i<=n;i++){scanf("%s",s+1);for (int j=1;j<=m;j++)  if (s[j]=='_') a[j][i]=1; else a[j][i]=0;}swap(n,m);}dp();printf("%d\n",f[now][1]);return 0;}


0 0
原创粉丝点击