4008: [HNOI2015]亚瑟王
Time Limit: 20 Sec Memory Limit: 512 MBSec Special JudgeSubmit: 878 Solved: 544
[ Submit][ Status][ Discuss]
Description
小 K 不慎被 LL 邪教洗脑了,洗脑程度深到他甚至想要从亚瑟王邪教中脱坑。
Input
输入文件的第一行包含一个整数 T,代表测试数据组数。
Output
对于每组数据,输出一行,包含一个实数,为这套卡牌在这一局游戏中造成的
Sample Input
3 2
0.5000 2
0.3000 3
0.9000 1
Sample Output
HINT
一共有 13 种可能的情况:
请注意可能存在的实数精度问题,并采取适当措施。
解题思路:技巧:当求概率正着推可能会有顺序问题时,可以
试着用1-反着推得概率。
首先这道题,可以确定每个点是在r轮中选择第i轮发动,或者干脆
都不发动,所以我们设f[i][j]表示还有j轮可以选择,当前牌为i的概率,
然后转移方程为
fi,j=fi−1,j∗(1−pi−1)j+fi−1,j+1∗(1−(1−pi−1)j+1)
然后答案就是
∑ni=1∑rj=1fi,j∗(1−(1−pi)j)∗di
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
int T,n,r;
long double p[230];
long double d[230];
long double f[230][230];
inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}
int main()
{
T=read();
while (T!=0)
{
memset(f,0,sizeof(f));
n=read(); r=read();
for (int i=1;i<=n;++i)
{
double x,y;
scanf("%lf%lf",&x,&y);
p[i]=x; d[i]=y;
}
long double ans=0;
f[0][r]=1;
for (int i=1;i<=n;++i)
for (int j=1;j<=r;++j)
{
f[i][j]=f[i-1][j]*pow(1-p[i-1],j)+f[i-1][j+1]*(1-pow(1-p[i-1],j+1));
ans+=f[i][j]*(1-pow(1-p[i],j))*d[i];
}
printf("%.10lf\n",(double)ans);
--T;
}
}