题意
有 n 张卡牌, 第 i 张卡牌有系数 p[i], d[i] .
一局游戏有 r 轮.
每轮从前往后遍历没有发动的卡牌, 每张卡牌有 p[i] 的概率发动.
若发动了这张卡牌, 那么会给敌方造成 d[i] 的伤害, 同时这张卡牌销毁, 并结束这一轮.
求一局游戏下来的期望伤害.
n <= 250, r <= 150, 0 < p[i] < 1, 1 <= d[i] <= 1000 .
分析
设 f[i][j] 表示第 i 张卡牌, 剩余 j 次机会的概率.
边界为 $f[1][r] = 1$ .
答案为 $\sum_{i = 1} ^ n \sum_{j = 1} ^ r d[i] \times f[i][j] \times (1 - {(1 - p_i)} ^ j)$ .
转移为:
第 i 张牌未发动: $f[i][j] \times {(1 - p_i)} ^ j \rightarrow f[i+1][j]$ .
第 i 张牌发动了: $f[i][j] \times (1 - {(1 - p_i)} ^ j) \rightarrow f[i+1][j-1]$ .
实现
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include <cmath> 6 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 7 #define db double 8 inline int rd(void) { 9 int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -1; 10 int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-‘0‘; return x*f; 11 } 12 13 const int N = 250; 14 const int R = 150; 15 16 int n, r, d[N]; db p[N], Pow[N][R]; 17 db f[N][R], sum; 18 19 int main(void) { 20 #ifndef ONLINE_JUDGE 21 freopen("authur.in", "r", stdin); 22 #endif 23 24 for (int nT = rd(), t = 1; t <= nT; t++) { 25 memset(p, 0, sizeof p), memset(d, 0, sizeof d); 26 n = rd(), r = rd(); 27 F(i, 1, n) scanf("%lf", p+i), d[i] = rd(); 28 29 F(i, 1, n) { 30 Pow[i][0] = 1; 31 F(j, 1, r) Pow[i][j] = Pow[i][j-1] * (1 - p[i]); 32 } 33 34 memset(f, 0, sizeof f), sum = 0, f[1][r] = 1; 35 F(i, 1, n-1) 36 F(j, 1, r) { 37 f[i+1][j] += Pow[i][j] * f[i][j]; 38 f[i+1][j-1] += (1 - Pow[i][j]) * f[i][j]; 39 } 40 F(i, 1, n) 41 F(j, 1, r) 42 sum += d[i] * f[i][j] * (1 - Pow[i][j]); 43 printf("%0.10lf\n", sum); 44 } 45 46 return 0; 47 }
时间: 2024-10-10 16:26:15