题面
题意
给出一张地图,请用“L”形地板覆盖所有非障碍的格子,“L”可以旋转,但两边的长度都必须大于0。
做法
因为数据范围非常小,所以可以用插头dp。
对于插头我们记录三种状态:
0:没有插头。
1:有插头,且是未拐过弯的“L”。
2:有插头,且是拐过弯的“L”。
然后在转移时分3*3=9种情况分别转移,有点耐心就好了。
代码
#include<iostream>
#include<cstdio>
#include<vector>
#define ll long long
#define N 110
#define M 20110520
using namespace std;
ll m,n,num,dp[2][200100],san[N],ans,li,lj;
char str[N];
bool mm[N][N],now,cur;
vector<ll>have[2];
inline ll get(ll u,ll v){return u/san[v-1]%3;}
inline ll chg(ll u,ll v,ll w){return u+(w-get(u,v))*san[v-1];}
inline void in(ll u)
{
if(!dp[now][u]) have[now].push_back(u);
dp[now][u]+=num;
if(dp[now][u]>M) dp[now][u]-=M;
}
int main()
{
ll i,j,k,t,p,q,kk;
cin>>m>>n;
for(i=1;i<=m;i++)
{
scanf("%s",str+1);
for(j=1;j<=n;j++)
{
if(m<n) mm[j][i]=(str[j]=='*');
else mm[i][j]=(str[j]=='*');
}
}
if(m<n) swap(m,n);
for(i=1;i<=m;i++) mm[i][0]=mm[i][n+1]=1;
for(i=0;i<=n+1;i++) mm[0][i]=mm[m+1][i]=1;
now=san[0]=num=1;
for(i=1;i<=n+1;i++) san[i]=san[i-1]*3;
in(0);
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
swap(now,cur);
have[now].clear();
for(kk=0;kk<have[cur].size();kk++)
{
k=have[cur][kk];
p=get(k,j),q=get(k,j+1);
t=chg(k,j,0),t=chg(t,j+1,0);
num=dp[cur][k];
if(mm[i][j]) in(k);
else if(!p&&!q)
{
if(!mm[i][j+1]) in(chg(k,j+1,1));
if(!mm[i+1][j]) in(chg(k,j,1));
if(!mm[i][j+1]&&!mm[i+1][j])
{
t=chg(k,j,2),t=chg(t,j+1,2);
in(t);
}
}
else if(!p&&q==1)
{
if(!mm[i+1][j]) in(chg(t,j,1));
if(!mm[i][j+1]) in(chg(k,j+1,2));
}
else if(!p&&q==2)
{
in(t);
if(!mm[i+1][j]) in(chg(t,j,2));
}
else if(p==1&&!q)
{
if(!mm[i+1][j]) in(chg(k,j,2));
if(!mm[i][j+1]) in(chg(t,j+1,1));
}
else if(p==1&&q==1) in(t);
else if(p==2&&!q)
{
in(t);
if(!mm[i][j+1]) in(chg(t,j+1,2));
}
dp[cur][k]=0;
}
}
swap(now,cur);
have[now].clear();
for(kk=0;kk<have[cur].size();kk++)
{
k=have[cur][kk];
num=dp[cur][k];
in(k*3);
dp[cur][k]=0;
}
}
cout<<dp[now][have[now][0]];
}