bzoj4008: [HNOI2015]亚瑟王

题目链接

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; 
} 
posted @ 2018-07-11 22:33  zzzzx  阅读(150)  评论(0编辑  收藏  举报