您的位置:首页 > 其它

【BZOJ4318】OSU!

2015-10-30 20:51 344 查看
Description

osu 是一款群众喜闻乐见的休闲软件。

我们可以把osu的规则简化与改编成以下的样子:

一共有n次操作,每次操作只有成功与失败之分,成功对应1,失败对应0,n次操作对应为1个长度为n的01串。在这个串中连续的 个1可以贡献 的分数,这x个1不能被其他连续的1所包含(也就是极长的一串1,具体见样例解释)

现在给出n,以及每个操作的成功率,请你输出期望分数,输出四舍五入后保留1位小数。

Input

第一行有一个正整数n,表示操作个数。接下去n行每行有一个[0,1]之间的实数,表示每个操作的成功率。

Output

只有一个实数,表示答案。答案四舍五入后保留1位小数。

Sample Input

3

0.5

0.5

0.5

Sample Output

6.0

HINT

【样例说明】

000分数为0,001分数为1,010分数为1,100分数为1,101分数为2,110分数为8,011分数为8,111分数为27,总和为48,期望为48/8=6.0

N<=100000

期望DP,和Easy那题一样

令f[i]为期望得分,g[i]期望长度,如果我们直接考虑把Easy的做法扩展到三次,会得到

f[i]=f[i−1]+(3∗g[i−1]2+3∗g[i−1]+1)∗a[i]

要注意的是平方的期望不等于期望的平方,因此要单独求出平方的期望,不能直接乘方来做.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 100010
using namespace std;
int n;
double f[MAXN],g1[MAXN],g2[MAXN],a[MAXN],ans;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%lf",&a[i]);
g1[i]=(g1[i-1]+1)*a[i];
g2[i]=(g2[i-1]+2*g1[i-1]+1)*a[i];
f[i]=f[i-1]+a[i]*(3*g2[i-1]+3*g1[i-1]+1);
}
printf("%.1f\n",f
);
}


以及Claris有神做法…

对于每个位置i,它成功时对答案的贡献为a[i]

对于两个位置i< j,它们中间都成功时,对答案的贡献为6a[i]a[i+1]…a[j-1]a[j]*(j-i)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 100010
using namespace std;
int n;
double ans;
double f[MAXN],g[MAXN],a[MAXN];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)  scanf("%lf",&a[i]),ans+=a[i];
for (int i=1;i<=n;i++)  g[i]=(g[i-1]+1)*a[i],f[i]=(f[i-1]+g[i-1])*a[i],ans+=f[i]*6;
printf("%.1f\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  期望DP