[BZOJ2554]Color 申必期望
传送门
有n个球排成一列,每个球都有一个颜色,用A-Z的大写字母来表示,我们每次随机选出两个球ball1,ball2,使得后者染上前者的颜色,求期望操作多少次,才能使得所有球的颜色都一样?
一行一个字符串,表示球的颜色
一行表示结果,精确到小数点后1位。
AAA
0.0
数据范围 对于10%的数据,n<=20 对于40%的数据,n<=200 对于50%的数据,n<=1000 对于100% 的数据,n <= 10000
Ctsc模拟赛By 洁妹
首先我们可以发现,这道题其实与字母本身以及具体位置无关,只和各字母的个数有关。
为了方便,下文我将“将所有字母的颜色染成a”简称为“a全部覆盖”。
对于一种颜色a,若我们求出颜色a能全部覆盖的概率以及期望步数,我们便可以求出答案。
具体的,答案为∑E′(a)×P′(a)。
显而易见,若a与b的个数相同,则E′(a)=E′(b)且P′(a)=P′(b)。
由此结论,我们可以定义E(x)表示当字母个数为x时全部覆盖的期望步数。
同理,定义P(x)表示当字母个数为x时全部覆盖的概率。
现在我们针对某一个字母全部覆盖进行讨论,对于别的不同的字母是等价的。
我们设这个字母是a,其余所有字母为b。
我们先计算P(x)。
显而易见,P(n)=1,P(0)=0。
对于一个字符串有x个a的状态Sx,可以在下一步直接转移到状态Sx−1,Sx+1 。对于所有的选法,可以算出有i×(n−i)种可以转移到Sx−1,有i×(n−i)种转移到Sx+1,明显这两种转移概率相等。
所以有P(x)=2P(x−1)+P(x+1),即P(x)−P(x−1)=P(x−1)−P(x−2)。所以数列P等差。
易得P(x)=nx。
至此,我们求出了P(x),之后我们计算E(x)。
由上面所得结论,可以发现每次操作后x变化的选择有2x(n−x),可以算出每次操作x变化的概率为T2x(n−x),所以操作使x变化的期望轮数为2x(n−x)T。
值得注意的是,由于我们算得期望E(x)表示有x个字母完全覆盖时的期望步数,而P(x−1)与P(x+1)不等,所以E(x−1)与E(x+1)对E(x)带来的贡献的权重也不等,而带来的贡献的权重比就等于它们的完全覆盖的概率比。
因此,我们可以得出 E(x)=P(x−1)+P(x+1)P(i−1)×E(i−1)+P(i+1)×E(i+1)+2x(n−x)T=2x(x−1)E(x−1)+(x+1)E(x+1)+2x(n−x)n(n−1) 值得注意的是,我们求答案时求的是∑nE(Cnti)×i。
我们不妨设f(x)=nE(x)×x。
则上式可化为 xf(x)×n=2xf(x−1)×n+f(x+1)×n+2x(n−x)n(n−1)
2f(x)=f(x−1)+f(x+1)+n−xn−1 f(x+1)=2f(x)−f(x−1)−n−xn−1 容易得到E(n)=0,又因为S0永远无法完全覆盖,所以对期望不够成贡献(但是仍然有一定概率被转移到),所以我们令E(0)=0。
所以可以得到f(n)=0,f(0)=0。
那么如何推出剩余的f(x)。
(下面的结论我是先找规律后证明的,过程较乱)
我们先将x=n−1带入上式,得到 f(n)=2f(n−1)−f(n−2)−(n−1)=0
我们假设有 (n−x+1)f(x)−(n−x)f(x−1)−(n−x)(n−1)=0
那么我们将f(x)=2f(x−1)−f(x−2)−n−x+1n−1带入,得到 2(n−x+1)f(x−1)−(n−x+1)f(x−2)−(n−1)−(n−x)f(x−1)−(n−x)(n−1)=(n−x+2)f(x−1)−(n−x−1)f(x−2)−(n−x+1)(n−1)=0
令X=x−1,则可以得出
(n−X+1)f(X)−(n−X)f(X−1)−(n−X)(n−1)=0 所以,上式成立。
所以,当X=1时,可以得到 nf(1)−(n−1)f(0)−(n−1)(n−1)=0
f(1)=n(n−1)2
至此,我们得到了f(0)与f(1)。
我们只需要递推计算f(x)即可。
答案为∑f(Cnti)。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;
template<typename __T>
inline void read(__T &x)
{
x=0;
int f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=x*10+c-'0';c=getchar();}
x*=f;
}
char str[10005];
int cnt[66];
double dp[10005];
int n;
int main()
{
scanf("%s",str);
n=strlen(str);
for(int i=0;i<n;i++)
cnt[str[i]-'A']++;
dp[1]=(n-1.0)*(n-1.0)/n;
for(int i=1;i<n-1;i++)
dp[i+1]=2*dp[i]-dp[i-1]-(n-1.0)/(n-i);
double ans=0;
for(int i=0;i<26;i++)
ans+=dp[cnt[i]];
printf("%.1lf\\n",ans);
return 0;
}
liu-runda
CQZhangyu
miskcoo
rising_shit
日期: 2018-04-11
标签: OI