题目链接(显然还没有找到原题)
虽说我现在才学会期望dp显得不太好,但没办法,谁让我比较菜~~,之前模拟赛已经考过几道类似的题了,但都一笔带过了,这次算是正式学习了一下这类题,于是就有了这篇题解。
首先看到k次方首先想到的就是我们在进行dp转移的时候不太方便,这个时候很自然的想到二项式定理去避免概率的重复计算,可以把k次冥的转移转换成for循环来做,这个时候就要去考虑转移方程了:设\(f[i]\)表示前i个宝箱的期望贡献,则显然有
\[f[i]^j=(f[i-1]+a[i])^j*p[i]+(f[i-1]+b[i])^j*(1-p[i]) \]二项式定理展开即为:
\[f[i]^j=(\sum _{k=0}^{j} C _{j}^{k}f[i-1]^ka[i]^k)*p[i]+(\sum _{k=0}^{j} C _{j}^{k}f[i-1]^kb[i]^k)*(1-p[i]) \]可以显然观察到两个式子不同的只有\((a[i]^k*p[i]/b[i]^k(1-p[i]))\),那么即可合并得:
\[f[i]^j=(\sum _{k=0}^{j} C _{j}^{k}f[i-1]^k(a[i]^k*p[i]+b[i]^k*(1-p[i]))) \]此时dp转移中的\(f[i]^j\)并不是很好处理,考虑将dp数组多开一维,令\(f[i][j]\)表示\(f[i]\)在j次方下的取值并可以令\(op[i][j]=a[i]^j*p[i]+b[i]^j*(1-p[i])\),就可以很好的处理dp转移中的各种状态。
总时间复杂度为\(O(nk^2)\),压线通过此题。
最后附上代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e4+5,mod=998244353;
int n,m,l,r,a[N],b[N],op[N][101],p[N][2];
int x,y,z,t,k,ans,f[N][101],c[101][101];
int quickpow(int a,int b){
int ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}return ans;
}
signed main(){
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>p[i][0]>>a[i]>>b[i];
p[i][1]=(mod+1-p[i][0])%mod;
}
c[1][0]=c[1][1]=c[0][0]=1;
for(int i=2;i<=k;i++){
c[i][1]=i;c[i][0]=1;
for(int j=2;j<=i;j++){
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
op[i][j]=(quickpow(a[i],j)*p[i][0]%mod+quickpow(b[i],j)*p[i][1]%mod)%mod;
}f[i][0]=1;op[i][0]=1;
}
for(int i=1;i<=k;i++)f[1][i]=op[1][i];
for(int i=2;i<=n;i++){
for(int j=1;j<=k;j++){
for(int kk=0;kk<=j;kk++){
f[i][j]=(f[i][j]+c[j][kk]*f[i-1][kk]%mod*op[i][j-kk]%mod)%mod;
}
}
}cout<<f[n][k];
return 0;
}
结束喽~~~~~
标签:27,int,题解,ans,101,csp,dp,mod From: https://www.cnblogs.com/houburzyx/p/18374335