Description
ls是一名集邮爱好者,他专门有一个栈来存放他的所有的邮票,但ls同时也是一名很粗心的人,有一些邮票可能放反了(上下颠倒),有一天他想把他的邮票拿出来向他的妹子炫耀,但因为有一些邮票可能反了,于是ls就想把那些邮票矫正方向,但ls特别懒,他觉得一张一张矫正太费时间了,即使是要给妹子看的,他也不想费太多时间,于是ls就想出了一种奇迹淫巧:
1.假设栈中还剩n张邮票,他每次从1到n中随机取一个整数k,然后取出栈中最上面的k张。
2.他会查看这k张中最上面的一张,如果它放反了,那么他就直接把这k张全部倒过来。
3.他直接把这k张放到桌上,然后准备给妹子炫耀,并且之后对这k张不做任何操作。
4.如果栈中还剩余邮票,那么回到步骤1。
当然,这毕竟是奇迹淫巧,而且是ls想出来的,桌上还是有可能有一些邮票放反了
那么ls想询问期望有多少张邮票放反了?
Solution
首先算出每张牌作为第一张的概率,第111张是111,第222张是1n1\over nn1,第333张是1×1n+1n×1n−1=1n−11\times {1\over n}+{1\over n}\times {1\over n-1}={1\over n-1}1×n1+n1×n−11=n−11,然后就发现第iii张就是1n−i+2(i≥2){1\over n-i+2}(i\ge2)n−i+21(i≥2)。
设上面的这个概率为ppp,第iii张牌翻转的概率为fif_ifi,那么有:fi=p+(1−p)fi−1(si=W)f_i=p+(1-p)f_{i-1}(s_i=W)fi=p+(1−p)fi−1(si=W)fi=(1−p)fi−1(si=C)f_i=(1-p)f_{i-1}(s_i=C)fi=(1−p)fi−1(si=C)
前后之间的联系还是挺妙的。
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=1000010;
const int inf=2147483647;
int n;long double f[Maxn][2];//0不翻 1翻
char str[Maxn];
int main()
{
scanf("%s",str+1);n=strlen(str+1);
if(str[1]=='C')f[1][0]=1,f[1][1]=0;
else f[1][0]=0,f[1][1]=1;
long double ans=0;
for(int i=2;i<=n;i++)
{
long double p=1.0/((long double)n-i+2);
if(str[i]=='C')f[i][0]=p+(1-p)*f[i-1][0];
else f[i][0]=(1-p)*f[i-1][0];
f[i][1]=1-f[i][0];
if(str[i]=='C')ans+=f[i][1];else ans+=f[i][0];
}
printf("%.15Lf",ans);
}