对于网格中的dp可以用轮廓线,如果有一些格子不能走就可以用插头dp了。
bzoj2331 地板
题目大意:用L型铺地n*m,有一些格子不能铺,求方案数。
思路:fi[i][j][s]表示铺到(i,j),轮廓线状态s,0表示没有插头,1表示插头没拐弯,2表示插头拐弯了,手动枚举转移。
注意:(1)按四进制好写;
(2)因为实际状态和四进制的差很多,所以用hash表来存储,防止mle和tle,同时使用滚动数组。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 105 #define M 200000 #define uu 50000 #define pp 20110520 using namespace std; int ai[N][N],fi[2][M]={0},point[uu],next[M],en[M],ha[2][M],tot[2],bt[N], nm,n,m,cur,la; int in(){ char ch=getchar(); while(ch!=‘_‘&&ch!=‘*‘) ch=getchar(); return ch==‘*‘;} void add(int s,int gi){ int i,x=s%uu; for (i=point[x];i;i=next[i]) if (ha[cur][en[i]]==s){ fi[cur][en[i]]=(fi[cur][en[i]]+gi)%pp; return; } ha[cur][++tot[cur]]=s;fi[cur][tot[cur]]=gi; next[++nm]=point[x];point[x]=nm;en[nm]=tot[cur];} void dp(){ int i,j,k,p,q,s,gi,ji;cur=1;la=0; tot[cur]=1;en[1]=0;ji=3; ha[cur][1]=0;fi[cur][1]=1; for (i=0;i<N;++i) bt[i]=i<<1; for (i=1;i<=n;++i){ for (j=1;j<=tot[cur];++j) ha[cur][j]=(ha[cur][j]<<2)&((1<<(bt[m+1]+1))-1); for (j=1;j<=m;++j){ cur^=1;la^=1; tot[cur]=nm=0; memset(fi[cur],0,sizeof(fi[cur])); memset(point,0,sizeof(point)); for (k=tot[la];k;--k){ s=ha[la][k];gi=fi[la][k]; if (!gi) continue; p=(s>>bt[j-1])&ji; q=(s>>bt[j])&ji; if (ai[i][j]){ if (!p&&!q) add(s,gi); }else if (!p&&!q){ if (!ai[i+1][j]) add(s+(1<<bt[j-1]),gi); if (!ai[i][j+1]) add(s+(1<<bt[j]),gi); if (!ai[i+1][j]&&!ai[i][j+1]) add(s+(1<<(bt[j-1]+1))+(1<<(bt[j]+1)),gi); }else if (!p){ s-=(1<<bt[j])*q; if (q==1){ if (!ai[i][j+1]) add(s+(1<<(bt[j]+1)),gi); if (!ai[i+1][j]) add(s+(1<<bt[j-1]),gi); }else{ add(s,gi); if (!ai[i+1][j]) add(s+(1<<(bt[j-1]+1)),gi); } }else if (!q){ s-=(1<<bt[j-1])*p; if (p==1){ if (!ai[i][j+1]) add(s+(1<<bt[j]),gi); if (!ai[i+1][j]) add(s+(1<<(bt[j-1]+1)),gi); }else{ add(s,gi); if (!ai[i][j+1]) add(s+(1<<(bt[j]+1)),gi); } }else if (p==1&&q==1){ s-=(1<<bt[j-1])+(1<<bt[j]); add(s,gi); } } } } } int main(){ int i,j;scanf("%d%d",&n,&m); memset(ai,127,sizeof(ai)); if (n<m){ for (i=1;i<=n;++i) for (j=1;j<=m;++j) ai[j][i]=in(); swap(n,m); }else for (i=1;i<=n;++i) for (j=1;j<=m;++j) ai[i][j]=in(); dp();printf("%d\n",fi[cur][1]); }
时间: 2024-10-27 12:35:18