BZOJ传送门
题目描述
ls是一名集邮爱好者,他专门有一个栈来存放他的所有的邮票,但ls同时也是一名很粗心的人,有一些邮票可能放
反了(上下颠倒),有一天他想把他的邮票拿出来向他的妹子炫耀,但因为有一些邮票可能反了,于是ls就想把那
些邮票矫正方向,但ls特别懒,他觉得一张一张矫正太费时间了,即使是要给妹子看的,他也不想费太多时间,于
是ls就想出了一种奇迹淫巧:
1.假设栈中还剩 n n n张邮票,他每次从 1 1 1到 n n n中随机取一个整数 k k k,然后取出栈中最上面的k张。
2.他会查看这 k k k张中最上面的一张,如果它放反了,那么他就直接把这 k k k张全部倒过来。
3.他直接把这 k k k张放到桌上,然后准备给妹子炫耀,并且之后对这 k k k张不做任何操作。
4.如果栈中还剩余邮票,那么回到步骤 1 1 1。
当然,这毕竟是奇迹淫巧,而且是ls想出来的,桌上还是有可能有一些邮票放反了
那么ls想询问期望有多少张邮票放反了?
输入输出格式
输入格式
输入仅一行一个字符串,长度 l e n ≤ 1000000 len\le 1000000 len≤1000000
第 i i i位为"C"则表示从栈顶数第 i i i张放的顺序是正确的,是"W"则表示从栈顶数第i张放的顺序是错误的。
输出格式
输出仅一行一个实数,表示放反的邮票的期望张数,相对或绝对误差不得超过 1 e − 9 1e-9 1e−9。
输入输出样例
输入样例#1:
WWCWCCW
输出样例#1:
2.333333333333
解题分析
首先我们来推一下第 i i i张邮票为某次抽牌第一张的概率。
第一张:很明显是 1 1 1。
第二张:只有单独抽出第一张邮票的时候第二轮才会是第一张, 所以为 1 n \frac{1}{n} n1。
第三张:第一张抽出后再使剩下邮票第二张成为第一张: 1 n × 1 n − 1 \frac{1}{n}\times \frac{1}{n-1} n1×n−11
抽出前两张后成为第一张: 1 n \frac{1}{n} n1。
所以概率为 1 n − 1 \frac{1}{n-1} n−11
同理可以推得这个概率序列为 1 , 1 n , 1 n − 1 . . . 1,\frac{1}{n},\frac{1}{n-1}... 1,n1,n−11...。
那么现在设 d p [ i ] [ 0 / 1 ] dp[i][0/1] dp[i][0/1]表示第 i i i张邮票不翻/翻的概率。
如果第 i i i张是正的, 我们又将它作为第一张抽出来, 它还是不会被翻过来。
同时如果它不是第一张, 只需要前面的一张牌也不翻过来就行了。
所以 d p [ i ] [ 0 ] = d p [ i − 1 ] [ 0 ] ∗ ( 1 − p ) + p dp[i][0]=dp[i-1][0]*(1-p)+p dp[i][0]=dp[i−1][0]∗(1−p)+p
相反, 如果它是反的, 作为第一张就会被翻过来。
这种情况必须它不是第一张而且前一张没被翻过来。
所以 d p [ i ] [ 0 ] = d p [ i − 1 ] [ 0 ] ∗ ( 1 − p ) dp[i][0]=dp[i-1][0]*(1-p) dp[i][0]=dp[i−1][0]∗(1−p)。
然后 d p [ i ] [ 1 ] = 1 − d p [ i ] [ 0 ] dp[i][1]=1-dp[i][0] dp[i][1]=1−dp[i][0]。
最后统计一下对应项的和就好了。
略卡精度。
代码如下:
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define MX 1000500
#define gc getchar()
#define db long double
db f[MX][2];
char str[MX];
int main(void)
{
scanf("%s", str + 1);
int len = std::strlen(str + 1);
if (str[1] == 'W') f[1][1] = 1;
else f[1][0] = 1;
for (R int i = 2; i <= len; ++i)
{
db p = 1.0 / (len - i + 2);
if (str[i] == 'W') f[i][0] = (1 - p) * f[i - 1][0];
else f[i][0] = p + (1 - p) * f[i - 1][0];
f[i][1] = 1 - f[i][0];
}
db ans = 0;
for (R int i = 1; i <= len; ++i)
{
if (str[i] == 'W') ans += f[i][0];
else ans += f[i][1];
}
printf("%.14Lf", ans);
}