先%%ISA
这题真难、
首先根据局数去枚举各种情况是铁定会爆的
而每次一个牌的概率还会受前面的牌用没用过的影响,所以不能分开dp
所以第一维表示当前牌,第二维表示还有j轮 注意存的是概率,而不是期望
最后答案就可以拆成所有终点状态的和,,也可以拆成 每次打出*相应概率 的和
可以把每一张牌对下面的影响拆成一层一层的,所以1~n开循环,取状态就取它上一张在这一轮没打出被跳过 和 上一张在上一轮被打出
注意这里只去被跳过的情况,因为我们循环干的是两件事:
1、每张牌在指定轮数被打出的贡献
2、这张牌跳过 对后面牌的概率影响
有了这两个就可以统计答案了,每个贡献会被前面的牌影响 每个影响后的贡献加起来就是答案
期望影响可以由上一张牌地推得到, 由于这张牌面临的情况必定是上一张牌两个转移之一,所以整合可以到一起算总体
如果还在考虑上一张牌,说明 中了 上一张牌被放弃了j局 {(1-p)^j}的概率
所以当前点的概率就等于 起点到上一个点的概率*上一个点到当前点的概率
概率*贡献=期望=答案
码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long double f[225][138],p[225],v[225],ans,pow[225][300];
double x,y;
int n,r,t,i,j;
int main()
{
scanf("%d",&t);
while(t--)
{
memset(f,0,sizeof(f));
scanf("%d%d",&n,&r);
for(i=0;i<=r;i++)
pow[0][i]=1;
for(i=1;i<=n;i++)
{
scanf("%lf%lf",&x,&y);
p[i]=x;
v[i]=y;
pow[i][0]=1;
for(j=1;j<=r;j++)
pow[i][j]=pow[i][j-1]*(1-p[i]);
}
f[0][r]=1;ans=0;
for(i=1;i<=n;i++)
for(j=1;j<=r;j++)
{
f[i][j]=f[i-1][j]*pow[i-1][j]+f[i-1][j+1]*(1-pow[i-1][j+1]);
ans+=f[i][j]*(1-pow[i][j])*v[i];
}
printf("%.10lf\n",(double)ans);
}
}