Codeforces 1810G - The Maximum Prefix(DP)
挺小清新的一道计数题。
首先先分析下这个“最大前缀和”,按照最朴素的思路就是扫一遍每个前缀,然后记录一下当前的 与前面的 ,但是如果你一直陷在这个思路上你就似了,因为按照这个思路做,你 DP 状态里需要记录 和 两个维度,算上下标一维总共是 ,并且没有任何办法省掉当中任何一个循环,所以哪怕解决 的问题都至少需要 。
考虑换一个角度处理这个“最大前缀和”,我们倒着 DP, 表示 后缀的最大前缀和,显然 。这样的好处一目了然:我们倒着 DP 的时候,只用记录一个维度也就是当前位置的 ,于是 的情况就迎刃而解了: 表示考虑到 ,目前 的概率。
但是还有一个问题,就是我们对 求答案,相当于每次在末尾加一个数,这就导致我们 DP 状态不得不重新计算,而每次重新计算复杂度又变成了三方。这个 bug 的修补方法也比较 trivial,倒着 DP 行不通,我们就再改回正着 DP 呗。我们将 DP 状态改为:设 表示当前在 ,在已知 的情况,随机填 的前缀,得分的期望值。考虑这样的转移:
- 如果 :
- 如果 :
初值 ,最终所求即为 。
代码非常短:
const int MAXN=5000; const int MOD=1e9+7; int qpow(int x,int e){int ret=1;for(;e;e>>=1,x=1ll*x*x%MOD)if(e&1)ret=1ll*ret*x%MOD;return ret;} int n,a[MAXN+5],dp[MAXN+5][MAXN+5]; void solve(){ scanf("%d",&n); for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)dp[i][j]=0; for(int i=1,x,y;i<=n;i++)scanf("%d%d",&x,&y),a[i]=1ll*x*qpow(y,MOD-2)%MOD; for(int i=0;i<=n;i++)scanf("%d",&dp[0][i]); for(int i=0;i<n;i++)for(int j=0;j<=n;j++){ if(j){ dp[i+1][j-1]=(dp[i+1][j-1]+1ll*a[i+1]*dp[i][j])%MOD; if(j<n)dp[i+1][j+1]=(dp[i+1][j+1]+1ll*(1-a[i+1]+MOD)*dp[i][j]%MOD); }else{ dp[i+1][0]=(dp[i+1][0]+1ll*(1-a[i+1]+MOD)*dp[i][j])%MOD; dp[i+1][1]=(dp[i+1][1]+1ll*(1-a[i+1]+MOD)*dp[i][j])%MOD; } } for(int i=1;i<=n;i++)printf("%d%c",dp[i][0]," \n"[i==n]); } int main(){ int qu;scanf("%d",&qu);while(qu--)solve(); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
2021-04-18 洛谷 P5331 - [SNOI2019]通信(CDQ 分治优化建图+费用流)
2021-04-18 Codeforces 1299D - Around the World(线性基+图论+dp)
2021-04-18 洛谷 P3270 - [JLOI2016]成绩比较(容斥原理+组合数学+拉格朗日插值)
2020-04-18 洛谷 P3215 [HNOI2011]括号修复 / [JSOI2011]括号序列(fhq-treap)
2020-04-18 关于我