bzoj 4008 亚瑟王 期望概率dp

时间:2023-03-09 09:07:46
bzoj 4008 亚瑟王 期望概率dp

对于这种看起来就比较傻逼麻烦的题,最关键的就是想怎么巧妙的设置状态数组,使转移尽可能的简洁。

一开始我想的是f[i][j]表示到第j轮第i张牌还没有被选的概率,后来发现转移起来特别坑爹,还会有重的或漏的情况。

于是改变想法:f[i][j]表示考虑到前i张牌,还剩j轮的概率

转移也就简单了,下一张牌有两种可能,选或不选:

f[i+1][j]=f[i][j]*(1-p[i+1])^j

f[i+1][j-1]=f[i][j]*(1-(1-p[i+1])^j)

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,r;
double po[225][140],p[225],k[225],f[225][140],ans;
int main()
{
register int i,j,T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&r);
for(i=1;i<=n;i++)
scanf("%lf%lf",&p[i],&k[i]);
for(i=1;i<=n;i++){
po[i][0]=1;
for(j=1;j<=r;j++)
po[i][j]=po[i][j-1]*(1-p[i]);
}
memset(f,0,sizeof(f));
f[0][r]=1; ans=0;
for(i=1;i<=n;i++)
{
for(j=0;j<=r;j++)
{
f[i][j]+=f[i-1][j]*po[i][j];
f[i][j]+=f[i-1][j+1]*(1-po[i][j+1]);
ans+=f[i-1][j+1]*(1-po[i][j+1])*k[i];
}
}
printf("%0.10lf\n",ans);
}
return 0;
}