题目
解法
设 (dp_{i,j}) 为识别前 (i) 首歌,需要 (j) 秒的概率(为什么会在后面提及)。容易想到枚举第 (i) 首歌已经听了 (k) 秒来转移:
[dp_{i,j}=sum_{k=1}^{t_i-1}dp_{i-1,j-k} imes (1-p_i)^{k-1} imes p_i
]
这是 (mathcal O(n^3)) 的。但是这个方程的 (k) 在指数上,也就是说,不同的 (j) 会引起系数的 整体 变化!具体地说,考虑 (dp_{i,j-1}) 到 (dp_{i,j}) 的变化:在 (j-1) 时 (kin[1,t_i-1]),转移到 (j) 相当于 (kin[2,t_i])。于是我们需要补 (k=1) 那一项,还要去除 (t_i) 那一项。这样复杂度降到了 (mathcal O(n^2))。
每首歌的贡献为 (1),所以直接将概率相加即可。
代码
#include <cstdio>
const int N = 5005;
int n, T, t[N];
double p[N], f[N][N], ans;
int read() {
int x = 0, f = 1; char s;
while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
return x * f;
}
double qkpow(double x, int y) {
double r = 1;
while(y) {
if(y & 1) r *= x;
x *= x; y >>= 1;
}
return r;
}
int main() {
n = read(), T = read();
for(int i = 1; i <= n; ++ i) p[i] = 1.0 * read() / 100, t[i] = read();
f[0][0] = 1;
for(int i = 1; i <= n; ++ i) {
double sum = 0, w = qkpow(1 - p[i], t[i] - 1);
for(int j = 1; j <= T; ++ j) {
sum *= 1 - p[i];
sum += f[i - 1][j - 1] * p[i];
if(j >= t[i]) {
sum -= f[i - 1][j - t[i]] * w * p[i];
f[i][j] += f[i - 1][j - t[i]] * w;
}
f[i][j] += sum; ans += f[i][j];
}
}
printf("%.9f
", ans);
return 0;
}