P1654 OSU!
Meaning
共有 次操作。每次操作有 的概率在当前位置填 1,否则填 0。
一串极长全 1 子串 的贡献为 ,求期望贡献。
Sol
考虑设计 dp 状态,令 表示以 结尾的极长全 1 子串的三次方贡献,同理令得 分别表示以 为结尾的极长全 1 子串的二次方贡献和一次方贡献。注意到我们的设定使得以 为结尾前面全为 1 的子串。考虑到期望线性性,那么显然有转移方程为
最后考虑如何统计答案,由于我们所设计的状态保证了以 为结尾的全 1 子串会产生贡献,当且仅当之前所有位置全为 1,而后位置为 0。那么显然答案为 。
Detail
- 对于期望 dp 的状态设计不够敏感;
- 容易在统计答案时忽略状态本身的意义。
Code
#include <iostream>
#include <cstdio>
#include <cctype>
using namespace std;
template <typename T>
inline T read() {
T x = 0, f = 1; char c = getchar();
while (!isdigit(c)) { if (c == '-') f = - f; c = getchar(); }
while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
return x * f;
}
#define lint long long int
#define ulint unsigned lint
#define readint read <int> ()
#define readlint read <lint> ()
const int inf = 1e9 + 1e7, MAXN = 1e5 + 1e1;
const lint INF = 1e18 + 1e9;
double f[MAXN], g[MAXN], h[MAXN], p[MAXN], Ans;
int n;
int main(void) {
n = readint;
for (int i = 1; i <= n; i ++) scanf("%lf", &p[i]);
for (int i = 1; i <= n; i ++) {
f[i] = p[i] * (f[i - 1] + 1.0);
g[i] = p[i] * (g[i - 1] + 2.0 * f[i - 1] + 1.0);
h[i] = p[i] * (h[i - 1] + 3.0 * g[i - 1] + 3.0 * f[i - 1] + 1.0);
}
for (int i = 1; i < n; i ++) Ans += (1.0 - p[i + 1]) * h[i];
printf("%.1lf\n", Ans + h[n]);
return 0;
}