Luogu P6275 [USACO20OPEN]Sprinklers 2: Return of the Alfalfa P
Link
显然种甜玉米和紫苜蓿的连通块会被一个左上-右下的格线分割。
设\(f_{j,i}\)表示考虑前\(j\)列前\(i\)行,现在格线在\((i,j)\)右侧的答案。
转移枚举从第\(j-1\)列进入第\(j\)列的行号即可,需要利用前缀和优化。
#include<cstdio>
#include<cstring>
const int N=2007,P=1000000007;
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
int mul(int a,int b){return 1ll*a*b%P;}
int f[N],g[N],cnt[N],pw[N*N],ipw[N*N];char str[N][N];
int main()
{
int n;scanf("%d",&n),g[0]=1;
for(int i=pw[0]=1;i<=n*n;++i) pw[i]=mul(2,pw[i-1]);
for(int i=ipw[0]=1,x=P-P/2;i<=n*n;++i) ipw[i]=mul(ipw[i-1],x);
for(int i=1;i<=n;++i) scanf("%s",str[i]+1);
for(int i=1;i<=n;++i) for(int j=(cnt[i]=cnt[i-1],1);j<=n;++j) cnt[i]+=(str[i][j]=='.');
for(int j=0;j<=n;++j)
{
memcpy(f,g,(n+1)<<2);
for(int i=0,s=0,x=(j>0)+(j<n);i<=n;++i)
{
if(str[i][j+1]^'W') inc(f[i],mul(s,cnt[i]>=x? pw[cnt[i]-x]:0));
if(str[i+1][j]^'W') inc(s,mul(g[i],ipw[cnt[i]]));
}
memcpy(g,f,(n+1)<<2),memset(f,0,(n+1)<<2);
}
printf("%d",g[n]);
}