题解 CF1810G The Maximum Prefix
挺小清新的一道计数题。
首先先分析下这个“最大前缀和”,按照最朴素的思路就是扫一遍每个前缀,然后记录一下当前的
考虑换一个角度处理这个“最大前缀和”,我们倒着 DP,
但是还有一个问题,就是我们对
- 如果
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}
-
初值
代码非常短:
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;
}