B. Let‘s Play Osu!
time limit per test:2 seconds
memory limit per test:256 megabytes
You‘re playing a game called Osu! Here‘s a simplified version of it. There are
n clicks in a game. For each click there are two outcomes: correct or bad. Let us denote correct as "O", bad as "X", then the whole play can
be encoded as a sequence of n characters "O" and "X".
Using the play sequence you can calculate the score for the play as follows: for every maximal consecutive "O"s block, add the square of its length (the number of characters "O")
to the score. For example, if your play can be encoded as "OOXOOOXXOO", then there‘s three maximal consecutive "O"s block "OO", "OOO",
"OO", so your score will be
22?+?32?+?22?=?17. If there are no correct clicks in a play then the score for the play equals to
0.
You know that the probability to click the
i-th (1?≤?i?≤?n) click correctly is
pi. In other words, the
i-th character in the play sequence has
pi probability to be "O",
1?-?pi to be "X". You task is to calculate the expected score for your play.
Input
The first line contains an integer
n (1?≤?n?≤?105) — the number of clicks. The second line contains
n space-separated real numbers
p1,?p2,?...,?pn
(0?≤?pi?≤?1).
There will be at most six digits after the decimal point in the given
pi.
Output
Print a single real number — the expected score for your play. Your answer will be considered correct if its absolute or relative error does not exceed
10?-?6.
Sample test(s)
Input
3 0.5 0.5 0.5
Output
2.750000000000000
Input
4 0.7 0.2 0.1 0.9
Output
2.489200000000000
Input
5 1 1 1 1 1
Output
25.000000000000000
Note
For the first example. There are 8 possible outcomes. Each has a probability of 0.125.
- "OOO"
?→? 32?=?9; - "OOX"
?→? 22?=?4; - "OXO"
?→? 12?+?12?=?2; - "OXX"
?→? 12?=?1; - "XOO"
?→? 22?=?4; - "XOX"
?→? 12?=?1; - "XXO"
?→? 12?=?1; - "XXX"
?→? 0.
So the expected score is
题目链接:http://codeforces.com/contest/235/problem/B
题目大意:长度为n的序列,每个位置上出现O的概率为pi,得分为连续k个O的k^2分,现在求得分的期望
题目分析:n^2 = 2 * C(2, n) + n,问题转化对于每段连续的O,求其子段长度大于等于2的段数*2再加上连续O的个数,比如OOO有三个O,两个OO,一个OOO,所以分数为2*3+3 = 9 = 3^3,这样问题就简单了,考虑每个点i,其能构成的长度为i,i-1,i-2,...,2,对应的概率为p1*p2*...*pi,p2*p3*...*pi,...,pi-1*pi
为方便表示,设(j, i)为p[j]*p[j+1]*...*p[i-1]*p[i],令dp[i] = Σ(j,i)其中1 <= j < i
则有dp[0] = 0,dp[2] = p[1]*p[2],dp[3] = p[1]* p[2] *p[3] + p[2]*p[3],可以看出
dp[i] = (dp[i - 1] + p[i - 1]) * p[i],dp[1]+dp[2]+dp[3] = p[1]*p[2] + p[2]*p[3] + p[1]*p[2]*p[3],发现正好是长度为3时,连续个数大于等于2的情况,所以之后我们把每个dp[i]的值乘2累加就是C(2,n)*2对答案的贡献,再加上Σpi,即每个O对答案的贡献就是最终的答案,所以可以写成
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int const MAX = 1e5 + 5; double dp[MAX], p[MAX]; int main() { int n; scanf("%d", &n); double ans = 0; for(int i = 1; i <= n; i++) { scanf("%lf", &p[i]); ans += p[i]; } for(int i = 2; i <= n; i++) { dp[i] = (dp[i - 1] + p[i - 1]) * p[i]; ans += 2 * dp[i]; } printf("%.10f\n", ans); }
仔细观察dp方程,dp[1] = 0,dp[i] = (dp[i - 1] + p[i - 1]) * p[i],这个递推式可以直接通过变量的循环实现,具体方法是先设一个tmp,在第i次循环时tmp就代表p[i],再设一个now表示多加一位时,新增的连续O长度大于1的情况,然后直接ans += 2 * now + tmp即长度大于1的每个要乘2再加本次添加的那个长度为1的
比如n=3时有p1,p2,p3计算过程为
i=1,tmp=p1,now=0,ans += p1,now = p1
i=2,tmp=p2,now=p1*p2,ans += 2*now + tmp = 2p1p2 + p2 + p1,now = p2 + p1p2
i=3,tmp=p3,now=p2p3 + p1*p2*p3,ans += 2*now + tmp = 2p2p3 + 2p1p2p3 + p3 + 2p1p2 + p2 + p1
所以ans = p1 + p2 + p3 + 2p1p2 + 2p2p3 + 2p1p2p3,这正好是我们定义的答案,所以还可以不开数组
#include <cstdio> int main() { int n; scanf("%d", &n); double ans = 0, tmp = 0, now; while(n --) { scanf("%lf", &tmp); now *= tmp; ans += 2 * now + tmp; now += tmp; } printf("%.10f\n", ans); }
版权声明:本文为博主原创文章,未经博主允许不得转载。
Codeforces 235B Let's Play Osu! (概率dp求期望+公式变形)