bzoj4008: [HNOI2015]亚瑟王
题目链接
题解
算出每张牌在r轮中打出的概率乘上权值
i在r轮中出现的概率$1 - (1 - p[i]) ^ r $
保证i本次为第一次打出概率,前面打了j张 概率$1 - (1 - p[i])^{r - j} \(
设\)dp[i][j]$ 表示,前i张牌,打出了j张的概率
转移分打不打i讨论一下
那么打i牌的概率为$\sum_j^{i ,r} dp[i - 1][j] * (1 - (1 - p[i])^{r - j}) $
题解
#include<bits/stdc++.h>
using namespace std;
int n,r;
const int maxn = 555;
double dp[maxn][maxn],p[maxn],g[maxn];
int d[maxn];
/*double pow(double x,int k) {
double ret = 1.0;
for(;k;k >>= 1,x *= x) if(k & 1) ret *= x;
return ret;
} */
double pw[maxn][maxn];
int main() {
int Qwq;
scanf("%d",&Qwq);
while(Qwq -- ) {
memset(dp,0,sizeof dp);
memset(g,0,sizeof g);
scanf("%d%d",&n,&r);
for(int i = 1;i <= n;++ i) scanf("%lf%d",p + i,d + i),pw[i][0] = 1.0;
for(int i = 1;i <= n;++ i) for(int j = 1;j <= r;++ j)
pw[i][j] = pw[i][j - 1] * (1.0 - p[i]);
dp[1][1] = g[1] = 1.0 - pw[1][r]; dp[1][0] = pw[1][r];
for(int i = 2;i <= n;++ i) {
for(int j = 0;j <= std::min(i,r);++ j) {
if(j) dp[i][j] += dp[i - 1][j - 1] * (1.0 - (pw[i][r - j + 1]));
if(i != j) dp[i][j] += dp[i - 1][j] * pw[i][r - j];
g[i] += dp[i - 1][j] * (1.0 - pw[i][r - j]);
}
}
double ans = 0;
for(int i = 1;i <= n;++ i) ans += g[i] * d[i];
printf("%.10lf\n",ans);
}
return 0;
}