被大佬口中的水题折磨了,看了很多博客,开始怀疑自己的智商,直到看到了这篇博客:
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;
}