![BZOJ4008: [HNOI2015]亚瑟王(期望dp) BZOJ4008: [HNOI2015]亚瑟王(期望dp)](https://image.shishitao.com:8440/aHR0cHM6Ly9ia3FzaW1nLmlrYWZhbi5jb20vdXBsb2FkL2NoYXRncHQtcy5wbmc%2FIQ%3D%3D.png?!?w=700&webp=1)
Time Limit: 20 Sec Memory Limit: 512 MBSec Special Judge
Submit: 1952 Solved: 1159
[Submit][Status][Discuss]
Description
小 K 不慎被 LL **了,*程度深到他甚至想要从亚瑟王*中脱坑。
Input
输入文件的第一行包含一个整数 T,代表测试数据组数。
Output
对于每组数据,输出一行,包含一个实数,为这套卡牌在这一局游戏中造成的
Sample Input
3 2
0.5000 2
0.3000 3
0.9000 1
Sample Output
HINT
一共有 13 种可能的情况:
Source
感觉期望的题都好绕啊qwq。。
首先根据期望的线性,每个位置对BOSS造成的伤害都是独立的。
根据期望的定义而且此题中每个位置只允许攻击一次,我们只需算出每个位置在$r$轮中出现的概率即可
这个概率为$1 - (1 - p[i])^r$,即总的概率减去一次都没出现的概率
但是这题有一个特殊限制“如果前面的打出了,那么本轮游戏结束”,也就是说如果$i - 1$位置打出了,那么$i$位置本次肯定是不能出现的
这样的话,如果$i$前面一共有$j$个位置打出了,也就是$i$有$j$次强制没被打出,那么$i$出现的概率为$1 - (1 - p[i])^{r - j}$
考虑这玩意儿如何计算,设$f[i][j]$表示前$i$个中强制打出了$j$个的概率
这显然是可以递推完成的,讨论一下这个位置是否打出就行了
那么$g[i] = \sum_i f[i][j] * (1 - (1 - p[i])^{r - j})$
最终答案为$ans = \sum g[i] * d[i]$
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define LL long long
using namespace std;
const int MAXN = , INF = 1e9 + ;
inline int read() {
char c = getchar(); int x = , f = ;
while(c < '' || c > '') {if(c == '-') f = -; c = getchar();}
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * f;
}
int N, R;
double f[][],/*前i轮中,恰好有j张牌发动了攻击的概率*/ P[], D[], PowP[][], G[];
void GetPow() {
for(int i = ; i <= N; i++) {
PowP[i][] = ;
for(int j = ; j <= R; j++)
PowP[i][j] = PowP[i][j - ] * ( - P[i]);
}
}
main() {
int QWQ;
scanf("%d", &QWQ);
while(QWQ--) {
memset(f, , sizeof(f));
scanf("%d %d", &N, &R);
for(int i = ; i <= N; i++)
scanf("%lf %lf", &P[i], &D[i]);
GetPow();
f[][] = G[] = - PowP[][R]; f[][] = PowP[][R];
for(int i = ; i <= N; i++) {
G[i] = ;
for(int j = ; j <= min(i, R); j++) {
if(j) f[i][j] += f[i - ][j - ] * ( - PowP[i][R - j + ]);
//发动攻击,那么R-j+1轮中不会出现
if(i != j) f[i][j] += f[i - ][j] * PowP[i][R - j];
//第i张牌始终没有出现过
G[i] += f[i - ][j] * ( - PowP[i][R - j]);
}
}
double ans = ;
for(int i = ; i <= N; i++)
ans += G[i] * D[i];
printf("%.10lf\n", ans);
}
return ;
}