P6275 [USACO20OPEN]Sprinklers 2: Return of the Alfalfa P 轮廓线DP
题意:
分析:
我们可以通过手调样例发现最后整张图会沿着一条线分为两个部分,所以我们利用这条分界线进行DP,我们设\(f[i][j][0]\)表示现在在第\(i\)行第\(j\)列的格子右下角的点,0表示该向右延展,1表示向下扩展,每次方向变化时需要除以二,因为有一个原来可放可不放的格子不得不放,情况减少了,转移的话看代码就能看懂
代码:
#include<bits/stdc++.h>
using namespace std;
namespace zzc
{
const int maxn = 2005;
const int mod = 1e9+7;
const int inv2 = 500000004;
bool vis[maxn][maxn];
int f[maxn][maxn][2];
int n,cnt=1;
char ch[maxn];
void work()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",ch+1);
for(int j=1;j<=n;j++)
{
if(ch[j]=='.')
{
vis[i][j]=true;
cnt=cnt*2%mod;
}
}
}
f[1][0][1]=cnt;
f[0][1][0]=cnt;
for(int i=0;i<=n;i++)
{
for(int j=0;j<=n;j++)
{
if(f[i][j][0])
{
f[i][j+1][0]=(f[i][j][0]+f[i][j+1][0])%mod;
if(vis[i+1][j]) f[i+1][j][1]=(f[i+1][j][1]+(long long)f[i][j][0]*inv2%mod)%mod;
}
if(f[i][j][1])
{
f[i+1][j][1]=(f[i+1][j][1]+f[i][j][1])%mod;
if(vis[i][j+1]) f[i][j+1][0]=(f[i][j+1][0]+(long long)f[i][j][1]*inv2%mod)%mod;
}
}
}
printf("%d\n",(f[n][n][0]+f[n][n][1])%mod);
}
}
int main()
{
zzc::work();
return 0;
}