攒RP 期望

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39439314/article/details/78429648

【问题描述】

  YYC 正在玩一个积累 RP 的游戏, 游戏在一个长度为 N 的序列上进行, YYC 在每一个位置上会有 Pi 的概率得到一点欧气, 1 - Pi 的概率得到一点非气, 然后用最终得到的序列给 YYC 计算 RP 变化值, 计算方式如下:
  1. 对于所有极长连续全欧序列, 设其长度为 x, 它会使得 YYC 的 RP增加 x^3 + K。
  2. 对于所有极长连续全非序列, 设其长度为 x, 它会使得 YYC 的 RP降低 x^2 + K。
  现在 YYC 想知道自己的 RP 在期望下会变化多少?

【输入格式】

  输入数据的第一行包含两个空格隔开的整数 N, K,接下来一行包含 N 个由空格隔开的浮点数 P1, P2, P3, … , PN, 意义如题所述。

【输出格式】

  输出仅一行一个浮点数, 表示 YYC 的 RP 的期望变化值。注意: 当你的答案与标准答案误差不超过 0.001 视为正确.

【输入样例】

16 1
0.642214
0.390778
0.670612
0.070373
0.717792
0.816008
0.499635
0.370708
0.330759
0.028899
0.220661
0.154958
0.700083
0.720874
0.659384
0.841728

【输出样例】

36.795074

【样例解释】

时间限制:1秒 内存限制:128M

【数据范围】

对于 20% 的数据, N ≤ 20.
对于 60% 的数据, N, K ≤ 100.
对于另外 20% 的数据, K = 0, N ≤ 1000000.
对于 100% 的数据, K ≤ 1000 , N ≤ 1000000 , 0 ≤ Pi < 1.

————————————————————————————————————————————————————

这个题实际上wxp大佬暑假来讲课的时候讲过。

但是。。。我回想起了。。。。。

那一度被概率期望和FFT所伤害的恐惧。。。。。。(虽然我现在还是不会FFT。。。之后再说)

说说题解吧。

O(N^2)的转移很简单:
设f(i,j,0/1)表示这是序列的第i个元素,算上i到之前连续j个元素都获得了欧气/非气的时候的RP期望值。
f(i,j,0)=( sum{ f(i-j,k,1) | 1<=k<=i-j }+ j^3 + K ) * Pi^j
f(i,j,1)=( sum{ f(i-j,k,0) | 1<=k<=i-j } - j^2 - K ) * (1-Pi)^j
f(0,0,0/1)=0
ans=sum{ f(N,x,0/1) | 1<=x<=N }
前缀和优化一下就是个O(N^2)的算法了。

开始考虑O(N)的转移。(考试的话就直接O(N^2)走人吧我很满足啊!感觉我通过这个题学了一波期望。。。)

设f1(i)表示的是到位置i为止欧气序列长度的期望:f1(i)=(f1(i-1)+1) * P[i]
设f2(i)表示的是到为止i为止欧气序列长度平方的期望:f2(i)=(f2(i-1) +2 * f1(i-1)+1) * P[i]

这个式子来源于期望的线性相加性质。

设随机变量X表示的是以当前序列最后一个元素结尾的欧气序列的长度,随机变量Y表示的是当前序列倒数第二个元素结尾的欧气序列的长度,那么

根据递推的关系,有P[i]的概率欧气序列的长度从X变为Y+1,有1-P[i]的概率欧气序列的长度变为0。
所以E(X)=E(Y+1) * P[i] + 0 * (1-P[i]) = (E(Y)+1) * P[i] -> f1(i)=(f1(i-1)+1) * P[i]

同样地,对于长度的平方,有P[i]的概率从Y^2变为(Y+1)^2,有1-P[i]的概率变为0
所以E(X)=E((Y+1)^2) * P[i]+0 * (1-P[i]) = (E(Y^2)+2 * E(Y)+1) * P[i] -> f2(i)=(f2(i-1)+2 * f1(i-1)+1) * P[i]

同样,对于长度的三次方,设为f3,就可以推导出:f3(i)=(f3(i-1)+3 * f2(i-1)+3 * f1(i-1)+1) * P[i]

不考虑K的话,直接考虑这个位置对于连续欧气序列长度的三次方贡献的期望(显然是跟上面那个f3不一样的,知道f3怎么推的话也就知道这个了),加上,然后减去对非欧序列长度二次方贡献的期望,最后算出来就是答案了。(PS:实在推不出来可以去看代码)

那么考虑一下K的情况,直接用奇偶性来考虑,考察开头和结尾两个位置的欧非情况就可以了(因为发现中间的分布情况完全对这个东西没有任何影响)。
有P[1] * P[N]的可能加K,有P[1] * (1-P[N])+P[N] * (1-P[1])的可能为0,有(1-P[1]) * (1-P[N])的可能减K。

然后就完了。(时间花于读入,然而有科学计数法。。。不想写优化)

现在每一次做期望的难题都是被伤害一次。。。。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<cctype>
using namespace std;
const int maxn=1000005;

int N,K;
double P[maxn],f1,f2,f3,g1,g2;
double ans;

int main()
{
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
    scanf("%d%d",&N,&K);
    for(int i=1;i<=N;i++)
        scanf("%lf",&P[i]);
    for(int i=1;i<=N;i++)
    {
        f3=(3*f2+3*f1+1)*P[i];//意义有变化
        f2=(f2+2*f1+1)*P[i];
        f1=(f1+1)*P[i];
        g2=(2*g1+1)*(1-P[i]);//意义有变化
        g1=(g1+1)*(1-P[i]);
        ans+=f3-g2;
    }
    ans+=K*P[1]*P[N]-K*(1-P[1])*(1-P[N]);
    printf("%.6lf\n",ans);
    return 0;
}
展开阅读全文

没有更多推荐了,返回首页