Description
osuosu是一款群众喜闻乐见的休闲软件。
我们可以把osos的规则简化与改编成以下的样子:
一共有nn次操作,每次操作只有成功与失败之分,成功对应,失败对应00,次操作对应为11个长度为的0101串。在这个串中连续的XX个可以贡献X3X3的分数,这XX个不能被其他连续的11所包含(也就是极长的一串,具体见样例解释)
现在给出nn,以及每个操作的成功率,请你输出期望分数,输出四舍五入后保留位小数。
Input
第一行有一个正整数nn,表示操作个数。接下去行每行有一个[0,1][0,1]之间的实数,表示每个操作的成功率。
(n≤105)(n≤105)
Output
只有一个实数,表示答案。答案四舍五入后保留11位小数。
Sample Input
3
0.5
0.5
0.5
Sample Output
6.0
Solution
由以及(x+1)2=x2+2x+1(x+1)2=x2+2x+1,令dp[i][1/2]dp[i][1/2]表示以ii结尾长度为的期望,dp[i][3]dp[i][3]表示前ii个数中的期望,那么有转移
dp[i][1]=dp[i−1]⋅p[i]dp[i][1]=dp[i−1]⋅p[i]
dp[i][2]=(dp[i−1][2]+2⋅dp[i−1][1]+1)⋅p[i]dp[i][2]=(dp[i−1][2]+2⋅dp[i−1][1]+1)⋅p[i]
dp[i][3]=(dp[i−1][3]+3⋅dp[i−1][2]+3⋅dp[i−1][1]+1)⋅p[i]+dp[i−1][3]⋅(1−p[i])dp[i][3]=(dp[i−1][3]+3⋅dp[i−1][2]+3⋅dp[i−1][1]+1)⋅p[i]+dp[i−1][3]⋅(1−p[i])
答案即为dp[n][3]dp[n][3],时间复杂度O(n)O(n)
Code
#include<cstdio>
using namespace std;
#define maxn 100005
int n;
double p[maxn],dp[maxn][3];
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][0]=(dp[i-1][0]+1)*p[i];
dp[i][1]=(dp[i-1][1]+2.0*dp[i-1][0]+1)*p[i];
dp[i][2]=(dp[i-1][2]+3.0*dp[i-1][1]+3.0*dp[i-1][0]+1)*p[i]+dp[i-1][2]*(1.0-p[i]);
}
printf("%.1f\n",dp[n][2]);
return 0;
}