神仙题,抄题解
用(tp_i)表示(i)这个技能在(r)轮中被使用过的概率
于是最后的答案就是(sum_{i=1}^nd_i*tp_i)
首先(tp_1=1-(1-p_1)^r),也就是连续(r)轮都没有使用的概率
之后往下的(tp)靠(dp)来求
设(dp_{i,j})表示在一共(r)轮里,前(i)个恰好有(j)个被发动的概率
那么
[tp_i=1-sum_{j=0}^rdp_{i-1,j}*(1-p_i)^{r-j}
]
还是先算一下这个技能一直都没有发动的概率,如果前面有(j)个技能使用了,那么那对应的轮次是一定不会使用当前技能的,剩下的轮次,也就是(r-j)轮我们让其不发动就好了
之后是(dp_{i,j})的转移
如果这一个技能并没有发动,那么就从(dp_{i-1,j})转移过来
[dp_{i,j}=dp_{i-1,j}*(1-p_i)^{r-j}
]
如果这个技能发动了,那么就需要从前面的(dp_{i-1,j-1})转移
[dp_{i,j}=dp_{i-1,j-1}*(1-(1-p_i)^{r-j+1})
]
我们还是先令技能(i)不发动,那么前面就会有(r-j+1)个轮次可能发动,我们都让其不发动,之后拿(1)减掉,就是发动的概率了
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 225
#define min(a,b) ((a)<(b)?(a):(b))
double dp[maxn][maxn];
double p[maxn];
int d[maxn],n,T,m;
double tp[maxn];
inline double quick(double a,int b)
{
double S=1.0;
while(b) {if(b&1) S*=a;b>>=1,a*=a;}
return S;
}
int main()
{
scanf("%d",&T);
while(T--)
{
memset(dp,0,sizeof(dp));
memset(p,0,sizeof(p));
memset(tp,0,sizeof(tp)),
memset(d,0,sizeof(d));
scanf("%d%d",&n,&m);
for(re int i=1;i<=n;i++)
scanf("%lf%d",&p[i],&d[i]);
dp[1][0]=quick((1-p[1]),m);
dp[1][1]=1-dp[1][0];
tp[1]=dp[1][1];
for(re int i=2;i<=n;i++)
{
for(re int j=0;j<=min(i-1,m);j++)
tp[i]+=dp[i-1][j]*quick((1-p[i]),m-j);
tp[i]=1-tp[i];
for(re int j=0;j<=min(i,m);j++)
{
dp[i][j]=dp[i-1][j]*quick((1-p[i]),m-j);
if(j) dp[i][j]+=dp[i-1][j-1]*(1-quick((1-p[i]),m-j+1));
}
}
double ans=0;
for(re int i=1;i<=n;i++)
ans+=tp[i]*d[i];
printf("%.10lf",ans),putchar(10);
}
return 0;
}