HNOI2015 亚瑟王
在分析题目之后,我们发现我们实际要求的其实只是每张牌发动技能的期望,它是在哪一轮发动不需考虑。
然后我们可以将题目稍做转换,有r个机会,n个人,第i的人得到机会的概率为pi.
我们可以设f[i][j]表示考虑完前i个人,还有j次机会的概率。
那么有两种转移方式:
1.第i+1个人没有得到机会,则f[i+1][j]+=f[i][j]*(1-pi+1)^j
2.第i+1个人得到一次机会,则f[i+1][j]+=f[i][j]*(1-(1-pi+1)^j));因为根据题意每个人最多得到一次机会,所以尽管可能有分到多次机会的概率,我们仍按一次来算,在这个转移可顺便求出每个人得到机会的概率。
时间复杂度O(nrT)
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<cstring> using namespace std; int dt,tj,i,n,m,j; double ans; struct card{ double p,d; }a[231]; double d[231],f[231][231],p[231][231]; int main() { scanf("%d",&dt); for(tj=1;tj<=dt;tj++){ scanf("%d%d",&n,&m); for(i=1;i<=n;i++)scanf("%lf%lf",&a[i].p,&a[i].d); memset(f,0,sizeof(f)); memset(d,0,sizeof(d)); f[m][0]=1; for(i=1;i<=n;i++)p[i][1]=1-a[i].p; for(i=2;i<=m;i++) for(j=1;j<=n;j++)p[j][i]=p[j][i-1]*(1-a[j].p); for(i=m;i>=1;i--){ for(j=0;j<n;j++){ f[i][j+1]+=f[i][j]*p[j+1][i]; f[i-1][j+1]+=f[i][j]*(1-p[j+1][i]); d[j+1]+=f[i][j]*(1-p[j+1][i]); } } ans=0; for(i=1;i<=n;i++)ans+=a[i].d*d[i]; printf("%.11lf\n",ans); } }