【BZOJ】4008: [HNOI2015]亚瑟王

题解

一个小数的一百多次方也没有爆,exm???

这个如果单看题面的话,这题非常的不好搞(什么题能告诉你它好搞><

我们放弃对每一局求贡献,转而求一个卡牌被使用的概率

怎么求,我们发现,只考虑前i - 1个被考虑后,有多少个局剩下了我们能用

这么想,我们从第一个数开始考虑,显然,它每次有R个局能用,它能被使用的概率就是\(1 - (1 - P_{1})^{R}\)
对于第二个数,他有概率是有R局都考虑它,还有概率是R - 1局考虑它,具体的概率还需要dp了

dp的方程就是
\(dp[i][j]\)表示考虑了前i个数,到了第i个数的时候,有j局还没有用
\(dp[i][j] = (1 - P_{i - 1})^{j}dp[i - 1][j] + (1 - (1 - P_{i - 1})^{j + 1})dp[i - 1][j + 1]\)只要考虑第i - 1个数有没有被使用就好

求期望就对每张牌统计一下概率就好

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
//#define ivorysi
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define mo 974711
#define RG register
#define MAXN 200005
using namespace std;
typedef long long int64;
typedef double db;
int T,N,R;
db f[305][150],powP[305][150],ans,P[350],D[350],s[350];
void Process() {
    ans = 0.0;
    scanf("%d%d",&N,&R);
    for(int i = 1 ; i <= N ; ++i) {
    scanf("%lf%lf",&P[i],&D[i]);
    }
    for(int i = 0 ; i <= N ; ++i) {
    powP[i][0] = 1.0;
    for(int j = 1 ; j <= R ; ++j) {
        powP[i][j] = powP[i][j - 1] * (1.0 - P[i]);
    }
    }
    memset(f,0,sizeof(f));
    memset(s,0,sizeof(s));
    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] * powP[i - 1][j] + f[i - 1][j + 1] * (1.0 - powP[i - 1][j + 1]);
        s[i] += f[i][j] * (1.0 - powP[i][j]); 
    }
    }
    for(int i = 1 ; i <= N ; ++i) ans += s[i] * D[i];
} 
void Solve() {
    scanf("%d",&T);
    while(T--) {
    Process();
    printf("%.10lf\n",ans);
    }
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ivorysi/p/9112213.html