【BZOJ】2331: [SCOI2011]地板

时间:2022-09-27 17:59:28

题目链接: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)}$

当然如果有障碍就不能走。


 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<cstring>
using namespace std;
#define maxn 10010
#define llg long long
#define SIZE 10007
#define md 20110520
#define maxnZT (1<<21)
#define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
llg n,m,code[maxn],zt[][maxnZT],v[][maxnZT],g[][],size[],now,la; struct node
{
llg pos,x,val;
}; vector<node>a[][SIZE]; void outcode(llg x){for (llg i=;i<=m;i++) code[i]=x&,x>>=;} void encode(llg p,llg val)
{
llg x=;
for (llg i=;i<=m;i++) x+=code[i]*(<<(i*));
llg wz=x%SIZE,E=a[p][wz].size();
for (llg i=;i<E;i++)
if (a[p][wz][i].x==x)
{
a[p][wz][i].val+=val; a[p][wz][i].val%=md;
v[p][a[p][wz][i].pos]+=val; v[p][a[p][wz][i].pos]%=md;
return ;
}
size[p]++;
node NEW;
NEW.pos=size[p],NEW.x=x,NEW.val=val;
a[p][wz].push_back(NEW);
zt[p][size[p]]=x; v[p][size[p]]=val;
} void init()
{
cin>>n>>m;
char ch;
for (llg i=;i<=n;i++)
for (llg j=;j<=m;j++)
{
ch=getchar();
while (ch!='*' && ch!='_') ch=getchar();
if (n<m) g[j][i]=(ch=='_');
else g[i][j]=(ch=='_');
}
if (n<m) swap(n,m);
} void init_a(llg p){for (llg i=;i<SIZE;i++) a[p][i].clear(); size[p]=;} void DP()
{
llg le,up,V;
encode(,);
for (llg i=;i<=n;i++)
{
for (llg k=;k<=size[now];k++) zt[now][k]*=;//轮廓线左移一格
for (llg j=;j<=m;j++)
{
now^=; la=now^; size[now]=;
init_a(now);
for (llg k=;k<=size[la];k++)
{
outcode(zt[la][k]);
le=code[j-],up=code[j],V=v[la][k];//提取左插头和上插头 if (g[i][j]==)
{
if (le== && up==) encode(now,V);
continue;
} if (!le && !up)
{
if (j<m && g[i][j+]==)
{
code[j-]=,code[j]=;
encode(now,V);
if (g[i+][j]==)
{
code[j-]=code[j]=;
encode(now,V);
}
}
if (g[i+][j]==)
{
code[j-]=,code[j]=;
encode(now,V);
}
continue;
} if (le && up)
{
if (le== && up==)
{
code[j-]=code[j]=;
encode(now,V);
}
continue;
} if (le== && up==)
{
if (g[i+][j]==)
{
code[j-]=;
encode(now,V);
}
if (g[i][j+]== && j<m)
{
code[j]=; code[j-]=;
encode(now,V);
}
continue;
} if (le== && up==)
{
if (j<m && g[i][j+]==)
{
code[j]=; code[j-]=;
encode(now,V);
}
code[j]=code[j-]=;
encode(now,V);
continue;
} if (le== && up==)
{
if (g[i+][j]==)
{
code[j-]=,code[j]=;
encode(now,V);
}
if (j<m && g[i][j+]==)
{
code[j-]=; code[j]=;
encode(now,V);
}
continue;
} if (le== && up==)
{
if (g[i+][j]==)
{
code[j]=,code[j-]=;
encode(now,V);
}
code[j-]=code[j]=;
encode(now,V);
continue;
}
}
}
}
} int main()
{
yyj("BZOJ2331");
init();
DP();
llg ans=;
bool pd;
for (llg i=;i<=size[now];i++)
{
outcode(zt[now][i]);
pd=true;
for (llg j=;j<=m;j++) if (code[j]) pd=false;
if (pd) ans+=v[now][i];
}
cout<<ans%md;
return ;
}