首页 > 其他分享 >Codeforces 1810G - The Maximum Prefix(DP)

Codeforces 1810G - The Maximum Prefix(DP)

时间:2023-04-18 18:55:52浏览次数:39  
标签:1810G 前缀 int Codeforces ret Prefix MAXN dp DP

挺小清新的一道计数题。

首先先分析下这个“最大前缀和”,按照最朴素的思路就是扫一遍每个前缀,然后记录一下当前的 \(sum\) 与前面的 \(mx\),但是如果你一直陷在这个思路上你就似了,因为按照这个思路做,你 DP 状态里需要记录 \(sum\) 和 \(mx\) 两个维度,算上下标一维总共是 \(n^3\),并且没有任何办法省掉当中任何一个循环,所以哪怕解决 \(k=n\) 的问题都至少需要 \(O(n^3)\)。

考虑换一个角度处理这个“最大前缀和”,我们倒着 DP,\(f_i\) 表示 \([i,n]\) 后缀的最大前缀和,显然 \(f_i=\max(f_{i+1}+a_i,0)\)。这样的好处一目了然:我们倒着 DP 的时候,只用记录一个维度也就是当前位置的 \(f_i\),于是 \(k=n\) 的情况就迎刃而解了:\(dp_{i,j}\) 表示考虑到 \(i\),目前 \(f_i=j\) 的概率。

但是还有一个问题,就是我们对 \(k=1,2,3,\cdots,n\) 求答案,相当于每次在末尾加一个数,这就导致我们 DP 状态不得不重新计算,而每次重新计算复杂度又变成了三方。这个 bug 的修补方法也比较 trivial,倒着 DP 行不通,我们就再改回正着 DP 呗。我们将 DP 状态改为:设 \(dp_{i,j}\) 表示当前在 \(i\),在已知 \(f_{i+1}=j\) 的情况,随机填 \([1,i]\) 的前缀,得分的期望值。考虑这样的转移:

  • 如果 \(j\ne 0\):
    • \(dp_{i,j}·a_{i+1}\to dp_{i+1,j-1}\)
    • \(dp_{i,j}·(1-a_{i+1})\to dp_{i+1,j+1}\)
  • 如果 \(j=0\):
    • \(dp_{i,j}·(1-a_{i+1})\to dp_{i+1,0}\)
    • \(dp_{i,j}·(1-a_{i+1})\to dp_{i+1,1}\)

初值 \(dp_{0,i}=h_i\),最终所求即为 \(dp_{i,0}\)。

代码非常短:

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;
}

标签:1810G,前缀,int,Codeforces,ret,Prefix,MAXN,dp,DP
From: https://www.cnblogs.com/tzcwk/p/Codeforces-1810G.html

相关文章

  • Codeforces Round 625 (Div. 1, based on Technocup 2020 Final Round) A. Journey Pl
    https://codeforces.com/contest/1320/problem/AA.JourneyPlanning题目大意:给定一组数,问我们ai-aj==i-j的时候就可以把ai的值加起来,问我们可以凑到的最大总值是多少?input6107191015output26input1400000output400000input7892611122914out......
  • Codeforces Round 866 (Div. 2) ABC
    https://codeforces.com/contest/1820A.Yura'sNewName题目大意:给定一个字符串,每次这个表情^^或者这个表情^_^就是合法的问我们这个字符串至少要添加多少东西使得怎么看都是合法的?input7^______^___^_^^^_^___^^_^^_^^^^^_^_^^___^^_output5511032#......
  • Codeforces Round 832 (Div2)
    SwapGameAlice和Bob两个人在玩游戏。有一个长度为\(n\)的序列\(a\),Alice和Bob两人轮流完成一个操作,Alice先开始。每个人可以将数列的第一个数减\(1\),并将它与后面序列的一个数进行交换,如果一个人操作之前发现当前序列中的第一个数为\(0\),这个人就输了。问如果两......
  • Codeforces Round 764 (Div. 3) -- E. Masha-forgetful
    **题目大意:取去模板串中的子串可以组成一个给定的目标串,每个子串可以用无数次,输出组成的所需的串的信息题目中的取得子串必须“>=2”很好的提示了我们,想到一个式子2*x+3*y可以等于任何数,所以从之前的串都取长度为2,为3。在进行匹配。**structnode{ intl,......
  • Codeforces Round 856 (Div2)
    CountingFactorizations任何一个正整数\(m\)都可以被唯一的分解为\(p_1^{e_1}\cdotp_2^{e_2}\ldotsp_k^{e_k}\)的形式。将正整数\(m\)的唯一质数分解转化为一个长度为\(2k\)的可重集合记为\(f(m)\)。\[f(m)=\{p_1,e_1,p_2,e_2,p_3,e_3,\ldots,p_k,e_k\}\]......
  • Codeforces Round 866 (Div. 2) A~C
     这场,非常快落!是难得对中国选手友好的时间(17:05) A观察一下,发现在连续的___中插入^就好,然后特判一下首尾,发现很像小学奥数的那个植树问题哇(注意特判一下只有一个^#include<bits/stdc++.h>usingnamespacestd;voidsolve(){strings;cin>>s;intn=s.len......
  • Codeforces Round 628 (Div. 2) A-D
    CodeforcesRound628(Div.2)A.EhAbAnDgCdvoidsolve(){intn=read();for(inti=1;i*i<=n;i++){intg=__gcd(i,n-i);if(g*g+i*(n-i)==n*g){cout<<i<<""<<n-i<<endl;bre......
  • Codeforces Round 862 (Div. 2)
    Preface补题ing这场思路挺顺的,早上上课的时候口胡了前5题下午都一发写过了然后想了30min的F1也Rush出来了,不过F2还是有点仙的做不动A.WeNeedtheZeroSB题,首先判断是否所有数的异或和等于\(0\)若不为\(0\)且\(n\)为偶数则无解,否则答案就是这个异或和本身#include<cstdio......
  • [Educational Codeforces Round 118 (Rated for Div. 2)]题解
    A题意:给定两个数,每一个数有两个属性,第一个属性是p1,第二个属性是p2.表示这个数有p2个后缀0.这个数本身等于p1后面加p2个0.问给你两个这种数,判断大小。思路:赛场上想到的:如果最终的长度不一样,可以直接根据长度判断。如果相等,就把后缀0加上直接比较大小就可以(比较字典序的大小),但......
  • Educational Codeforces Round 110 (Rated for Div. 2) C. Unstable String(状态机)
    https://codeforces.com/contest/1535/problem/C题目大意:给定一个字符串s,由10?组成:?每次都可以任意替换成0或者1问我们这个子字符串中,能够组成010101这样两两互不相等的字符串的数量最大是多少?input30?10????10??1100output8625#include<bits/stdc++.h>usin......