CF1842G Tenzing and Random Operations
题意
给定一个 \(n\) 和 \(a_i\) 和 \(v\)。有 \(m\) 次操作,每次等概率选择 \(i\in [1,n]\),将 \(\forall j\in [i,n],a_j\leftarrow a_j+v\),求操作结束后 \(\prod a_i\) 期望。
\(n\leq 5000\),\(m,v,a_i\leq 10^9\)
做法
考虑组合意义,\(\prod a_i\) 相当于一个人从 \(i\) 走向 \(i+1\) 有 \(v\) 种方案。那么加法操作就相当于我们可以在 \(p\) 后每次多有 \(v\) 条方案可以走。那么我们考虑动态规划,设 \(f_{i,j}\) 表示前 \(i\) 个位置,已经用了 \(j\) 个操作的方案数。那么有转移:
\[f_{i,j}a_{i+1}\rightarrow f_{i+1,j}
\]
表示不用操作,
\[f_{i,j}jv\rightarrow f_{i+1,j}
\]
表示用原来的操作,
\[f_{i,j}(i+1)(m-j)v\rightarrow f_{i,j+1 }
\]
表示从旧的位置选择一个位置,填入 \(m-j\) 即一个还没有使用过的工具,那么答案就是:
\[\frac{\sum f_{n,i}n^{m-i}}{n^m}
\]
即表示剩下的 \(m-i\) 个操作不重要可以在 \(n\) 个位置中随便填。复杂度 \(O(n\cdot\min(n,m))\)。
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;
typedef long long ll;
const int MAXN=5005;
const int MOD=1e9+7;
int ksm(int a,int b){
int ans=1;
while(b){
if(b&1){
ans=1ll*ans*a%MOD;
}
a=1ll*a*a%MOD;
b>>=1;
}
return ans;
}
int n,m,v,a[MAXN],f[MAXN][MAXN];
#define add(x,y) (((x)+=(y))>=MOD&&((x)-=MOD));
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m>>v;
rep(i,1,n){
cin>>a[i];
}
f[0][0]=1;
rep(i,0,n-1){
rep(j,0,min(m,i)){
add(f[i+1][j],1ll*f[i][j]*a[i+1]%MOD);
add(f[i+1][j],1ll*f[i][j]*j%MOD*v%MOD);
add(f[i+1][j+1],1ll*f[i][j]*(i+1)%MOD*(m-j)%MOD*v%MOD);
}
}
int ans=0;
rep(i,0,min(n,m)){
add(ans,1ll*f[n][i]*ksm(n,m-i)%MOD);
}
ans=1ll*ans*ksm(ksm(n,m),MOD-2)%MOD;
cout<<ans<<"\n";
return 0;
}

浙公网安备 33010602011771号