[HNOI2015]亚瑟王(概率dp)
题面太长了就不复制了,传送门
一道做了还是很懵逼的题目,感觉以后碰到类似的还是不会,果然HNOI题目很皮。
题解传送
补充一下吧。//感觉他的博客已经写得很好了......Orz 需要的可以两边一起看
1.期望的线性性质 E(x+y)=E(x)+E(y) //x,y是两个不同的事件
E(kx)=kE(x) //(k为常数)
2.单独考虑每张牌的概率的时候,影响其的只有他前面选了几张。
例如在前j轮里,在牌i(假设i>j)前面有k张牌发动了(不包括i)。
若k<j,意味着还有牌在包括i的后面发动了,这时是不是我们考虑了i是否发动,所以会有概率做贡献
若k==j,意味着j轮内发动的牌都在i前面,依题意,我们不会考虑i是否发动,所以不会有概率做贡献
大家尽量yy一下,语言表达能力有限
3.补充一下这里吧,自己看的时候感觉写的不是很清楚:
F[i][j]表示在所有r轮中,前i张卡一共出了j张的概率,那么就可以用O(n)的时间算出Fp[i](i>0)
枚举前i−1轮选了j张牌,那么有j轮不会考虑到第i张牌,也就是有r−j轮会考虑到第i张牌
//根据状态的定义,我们选了j张牌是不是意味着我们已经进行了j轮了,这时F[i−1][j]就意味着
在前i−1张牌中我们有j张发动了,根据题目条件,一旦发动回合结束,即前j轮根本就没机会来到第i张牌,所以剩下的r−j轮就会考虑到i,会对Fp[i]做出贡献。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
double p[221],f[221][133],all[221];
int d[221];
int main()
{
int t,n,r;
scanf("%d",&t);
while(t--)
{
memset(f,0,sizeof(f));
memset(all,0,sizeof(all));
scanf("%d%d",&n,&r);
for(int i=1;i<=n;i++)
{
scanf("%lf%d",&p[i],&d[i]);
}
f[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=r;j++)
{
f[i][j]+=f[i-1][j]*pow(1-p[i],r-j);
if(j>0) f[i][j]+=f[i-1][j-1]*(1-pow(1-p[i],r-j+1));
all[i]+=f[i-1][j]*(1-pow(1-p[i],r-j));
}
}
double ans=0;
for(int i=1;i<=n;i++)
{
ans+=all[i]*d[i];
}
printf("%.10lf\n",ans);
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步