BZOJ 4318 OSU!【期望DP】

被大佬口中的水题折磨了,看了很多博客,开始怀疑自己的智商,直到看到了这篇博客:
https://blog.csdn.net/PoPoQQQ/article/details/49512533.
Orz 还是要自己梳理一下。
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4318.

题意:

一个长度为n的01串,给定每个位置为1的概率为p[i],这个串得到的分数是这个串所有的极大连续 1 串的长度的立方和,比如011100011的分数就是33+23=35。

思路:

我们先假设这个串是固定的,我们可以整体的求出所有连续极大 1 串,然后再算立方和。
但是在这里,我们不那样做,我们用每一位对分数的贡献度计算出最后的分数。如果这一位是1,那么它的贡献度就是(x+1)3-x3=3x2+3x+1,这里x是这一位之前的最长的连续 1 串后缀长度,我们在计算的时候就要维护x。这样把每一位的贡献度加起来也可以得到答案。
知道了这一点,那么现在就是确切的数字变成了期望。
玄乎一点说就是原本的固定的串 0 和 1 的概率只有0和1,现在是加了概率。
那以前x是确切的数,现在我们要用它的期望,这一位的贡献度也要乘上概率变成期望贡献度,这样加起来就是期望分数了。
具体做法是维护x和x2的期望,x的意义同上所述。

代码:

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int n;
double p[maxn],dp[maxn],dp2[maxn],ans;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lf",&p[i]);
    for(int i=1;i<=n;i++)
    {
        dp[i]=(dp[i-1]+1)*p[i];
        dp2[i]=(2*dp[i-1]+dp2[i-1]+1)*p[i];//有p[i]的概率变为x*x+2*x+1,有1-p[i]的概率变为0,加起来就是期望
        ans+=p[i]*(3*dp2[i-1]+3*dp[i-1]+1);
    }
    printf("%.1lf\n",ans);
    return 0;
}


猜你喜欢

转载自blog.csdn.net/qq_44607936/article/details/99875838
今日推荐