[USACO20OPEN]Sprinklers 2: Return of the Alfalfa P
LXV.[USACO20OPEN]Sprinklers 2: Return of the Alfalfa P
首先,一个合法的方案,肯定是有一条从左到右向下延伸的轮廓线:
例如:
其中,蓝色系格子是玉米,红色系格子是苜蓿;浅蓝色位置必须放玉米喷射器,深红色格子必须放苜蓿喷射器。深蓝和浅红格子放不放均可。更一般地说,所有的转角处,都是必须放喷射器的位置。
因此我们可以考虑DP:
假设一定至少放了一个玉米喷射器(有可能有没有任何玉米喷射器的情况,但当且仅当左下角可以放喷射器时,这时只要在左下角放一个苜蓿,其他位置就可以随便放或不放喷射器了),则设表示在位置放了一个玉米时的方案数。
我们思考一下,当位置已经被放入玉米后,有哪些位置的发射器种类以及决定了:
如图,五角星格子就是,
那么左下角的深蓝色格子肯定已经被决定了;
第行上,肯定有一个深红格子存在(不然行就没有颜色了),因此实际上,只有以为左上角的矩形,里面的颜色尚未决定。
因此我们设一个前缀和,表示以为左上角的矩形里面有多少个位置没有牛。
先考虑初始化。
- 位置中,即不位于第行。
如图,则位置必有一个苜蓿。显然,只有位置不是牛,该位置才可以作为起始点。
则。
- 有。
位置的那个苜蓿不需要放,直接有
。
考虑转移。
我们枚举一个,且。
则位置肯定有个苜蓿。如果位置没有牛,则可以转移。
如图,黄星要想从紫星转移来,那么深红位置是必须放置苜蓿的。
则有
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,s[2010][2010],f[2020][2020],bin[4001000],res;
char g[2010][2010];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%s",g[i]+1);
for(int i=n;i;i--)for(int j=n;j;j--)s[i][j]=s[i+1][j]+s[i][j+1]-s[i+1][j+1]+(g[i][j]=='.');
bin[0]=1;
for(int i=1;i<=s[1][1];i++)bin[i]=(bin[i-1]<<1)%mod;
// for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)printf("%d ",s[i][j]);puts("");}
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
if(g[i][j]=='W')continue;
if(g[i-1][1]=='.')f[i][j]=bin[s[1][1]-s[i][j+1]-2];
if(i==1)f[i][j]=bin[s[1][1]-s[i][j+1]-1];
for(int k=1;k<i;k++)for(int l=1;l<j;l++){
if(g[k][l]=='W'||g[i-1][l+1]=='W')continue;
(f[i][j]+=1ll*bin[s[k][l+1]-s[i][j+1]-2]*f[k][l]%mod)%=mod;
}
if(g[n][j+1]=='.')(res+=1ll*f[i][j]*bin[s[i][j+1]-1]%mod)%=mod;
if(j==n)(res+=f[i][j])%=mod;
}
// for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)printf("%d ",f[i][j]);puts("");}
if(g[n][1]=='.')(res+=bin[s[1][1]-1])%=mod;
printf("%d\n",res);
return 0;
}
很明显这种东西是的,期望得分。考虑优化。
初始化过程是的,没问题。关键是转移的地方。
我们搬出式子:
先把这个东西拆成和有关的和有关的部分:
再调整求和顺序:
然后设一个前缀和
往里面一代:
这样复杂度就被优化成了,期望得分。
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int inv2=5e8+4;
int n,s[2010][2010],f[2020][2020],bin[4001000],inv[4001000],res,sum[2020][2020];
char g[2010][2010];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%s",g[i]+1);
for(int i=n;i;i--)for(int j=n;j;j--)s[i][j]=s[i+1][j]+s[i][j+1]-s[i+1][j+1]+(g[i][j]=='.');
bin[0]=inv[0]=1;
for(int i=1;i<=s[1][1];i++)bin[i]=(bin[i-1]<<1)%mod,inv[i]=(1ll*inv[i-1]*inv2)%mod;
// for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)printf("%d ",s[i][j]);puts("");}
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
if(g[i][j]!='W'){
if(g[i-1][1]=='.')f[i][j]=bin[s[1][1]-s[i][j+1]-2];
if(i==1)f[i][j]=bin[s[1][1]-s[i][j+1]-1];
for(int k=1;k<j;k++){
if(g[i-1][k+1]=='W')continue;
(f[i][j]+=1ll*sum[i-1][k]*inv[s[i][j+1]+2]%mod)%=mod;
}
if(g[n][j+1]=='.')(res+=1ll*f[i][j]*bin[s[i][j+1]-1]%mod)%=mod;
if(j==n)(res+=f[i][j])%=mod;
}
sum[i][j]=(1ll*f[i][j]*bin[s[i][j+1]]+sum[i-1][j])%mod;
}
// for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)printf("%d ",f[i][j]);puts("");}
if(g[n][1]=='.')(res+=bin[s[1][1]-1])%=mod;
printf("%d\n",res);
return 0;
}
继续尝试优化。
发现我们现在就可以设一个
则直接有
复杂度,期望得分。
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int inv2=5e8+4;
int n,s[2010][2010],f[2020][2020],bin[4001000],inv[4001000],res,sum1[2020][2020],sum2[2020][2020];
char g[2010][2010];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%s",g[i]+1);
for(int i=n;i;i--)for(int j=n;j;j--)s[i][j]=s[i+1][j]+s[i][j+1]-s[i+1][j+1]+(g[i][j]=='.');
bin[0]=inv[0]=1;
for(int i=1;i<=s[1][1];i++)bin[i]=(bin[i-1]<<1)%mod,inv[i]=(1ll*inv[i-1]*inv2)%mod;
// for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)printf("%d ",s[i][j]);puts("");}
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
if(g[i][j]!='W'){
if(g[i-1][1]=='.')f[i][j]=bin[s[1][1]-s[i][j+1]-2];
if(i==1)f[i][j]=bin[s[1][1]-s[i][j+1]-1];
(f[i][j]+=1ll*sum2[i-1][j-1]*inv[s[i][j+1]+2]%mod)%=mod;
if(g[n][j+1]=='.')(res+=1ll*f[i][j]*bin[s[i][j+1]-1]%mod)%=mod;
if(j==n)(res+=f[i][j])%=mod;
}
sum1[i][j]=(1ll*f[i][j]*bin[s[i][j+1]]+sum1[i-1][j])%mod;
sum2[i][j]=(sum2[i][j-1]+(g[i][j+1]=='W'?0:sum1[i][j]))%mod;
}
// for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)printf("%d ",f[i][j]);puts("");}
if(g[n][1]=='.')(res+=bin[s[1][1]-1])%=mod;
printf("%d\n",res);
return 0;
}
分类:
DP
, 数据结构——差分/前缀和
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?