BZOJ4318 OSU!¶
题意¶
给定一个序列,每个位置为 \texttt{o} 的几率为 p_i ,为 \texttt{x} 的几率为 1 - p_i 。对于一个 \texttt{ox} 序列,连续 x 长度的 \texttt{o} 会得到 x^3 的收益,问最终得到的 \texttt{ox} 序列的期望收益是多少?
题解¶
这题和20181106的考试题很像( x^2 变成了x^3),属于升级版,和BZOJ3450有一定联系。
可以将题目转化一下,变成以每个点为右端点的区间长度的期望的立方的和。
设 g[i] 为以 i 位置为右端点的的期望的立方的和。
由于此时变为区间的立方,所以在转移 g 时不能简单的由以 i 为右端点的长度的期望转移。
(如果问题改为收益为 x^2 可以,因为 (x+1)^2-x^2=x\times 2-1 )
考虑 g[i] 如何由 g[i-1] 转移而来。
我们发现如果 i-1 产生收益的期望 g[i-1]=x^3 ,那么 i 可以产生的收益的期望为 ((x+1)^3 - x^3) \times p_i (其中 p_i 为 i 产生 \texttt{o} 的概率)。
然后将括号中的式子用立方差公式处理一下:
相当于只需要知道区间长度期望与区间长度立方的期望就行了。
于是设 f[i][j] 表示,以第 i 个位置结尾的区间长度的 i 次方的期望。
有转移方程:
f[1][i] = f[1][i-1]\times p_i
f[2][i] = (2 * f[2][i-1] - 1) \times p_i (这个在之前提到了)
于是可以得到 g 的转移式:
最终的答案就是 \sum_{i=1}^{N}g[i] ,在程序中可以将 g 记成前缀和答案就是 g[N]
程序¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <cstring> #define MAX_N 100007 #define reg register typedef long long ll; int N; double p[MAX_N], f[2][MAX_N], g[MAX_N]; template <typename _T> inline void read (_T& x) { x = 0; reg _T y = 1; reg char c = getchar(); while (c < '0' || '9' < c) { if (c == '-') y = -1; c = getchar(); } while ('0' <= c && c <= '9') x = x * 10 + c - '0', c = getchar(); x *= y; } inline void dp () { for (int i = 1; i <= N; ++i) f[0][i] = (f[0][i - 1] + 1) * p[i]; for (int i = 1; i <= N; ++i) f[1][i] = (f[1][i - 1] + 2 * f[0][i - 1] + 1.0) * p[i]; for (int i = 1; i <= N; ++i) g[i] = g[i - 1] + (3.0 * f[1][i - 1] + 3.0 * f[0][i - 1] + 1.0) * p[i]; printf("%.1lf\n", g[N]); } int main () { read(N); for (int i = 1; i <= N; ++i) scanf("%lf", p + i); dp(); return 0; } |