[BZOJ 4844] [Neerc2016]Foreign Postcards

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 len1000000

i i i位为"C"则表示从栈顶数第 i i i张放的顺序是正确的,是"W"则表示从栈顶数第i张放的顺序是错误的。

输出格式

输出仅一行一个实数,表示放反的邮票的期望张数,相对或绝对误差不得超过 1 e − 9 ​ 1e-9​ 1e9

输入输出样例

输入样例#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×n11

​ 抽出前两张后成为第一张: 1 n \frac{1}{n} n1

​ 所以概率为 1 n − 1 \frac{1}{n-1} n11

同理可以推得这个概率序列为 1 , 1 n , 1 n − 1 . . . 1,\frac{1}{n},\frac{1}{n-1}... 1,n1,n11...

那么现在设 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[i1][0](1p)+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[i1][0](1p)

然后 d p [ i ] [ 1 ] = 1 − d p [ i ] [ 0 ] dp[i][1]=1-dp[i][0] dp[i][1]=1dp[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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值