一、题目
题目描述
一个口袋中装有巧克力,巧克力的颜色有
c种。现从口袋中取出一个巧克力,若取出的巧克力与桌上某一已有巧克力颜色相同,则将两个巧克力都取走,否则将取出的巧克力放在桌上。设从口袋中取出每种颜色的巧克力的概率均等。求取出
n个巧克力后桌面上剩余
m个巧克力的概率。
数据范围
1≤c≤100,1≤n,m≤1000000
二、解法
发现最后还在桌面上的巧克力一定是出现奇数次的,我们把奇数和偶数的情况分别表示成母函数(0奇1偶),因为我们还需要考虑排列,相同颜色的排列必须要消去,所以我们把这个任务交给母函数的系数,最后在乘上
n!即可:
f0(x)=1!x+3!x3+5!x5+.....
f1(x)=0!1+2!x2+4!x4+.....我们考虑用自然底数
e表示它们的闭形式,先给出一个结论,
ex=(1+n1)nx=1+1!x+2!x2+....下面给出证明:
结论一:
ex等于
ex的求导
先证明等价无穷小,即
ex−1=x(
x趋近于
0),我们先设
y=ex−1把两边取对数,
x=ln(y+1),因为
x趋近于
0,所以
ln(y+1)趋近于
1,推出
y趋近于
0,所以
ex−1=x
然后我们暴力对
ex 求导:
Δxex+Δx−ex=Δxex⋅(eΔx−1)=ex运用了等价无穷小,问题得证。
结论二:泰勒展开很香
我们把
ex在
x=0出泰勒展开,得到(注,
f(x)=ex):
f(x)=f(x0)+1!f′(x0)(x−x0)+2!f′′(x0)(x−x0)2....
f(x)=1+1!x+2!x2+3!x3+......结合了结论一,故原等式成立。
然后我们可以把奇数和偶数的母函数用
ex表示出来:
f0(x)=2ex−e−x
f1(x)=2ex+e−x所以我们要取出
m个颜色使它为奇数,取出
c−m个颜色使它为偶数,把所有颜色整合后的母函数表示出来:
G(x)=Ccm⋅(2ex−e−x)m⋅(2ex+e−x)c−m
G(x)=2−c⋅Ccm⋅(ex−e−x)m⋅(ex+e−x)c−m
G(x)=2−c⋅Ccmi=0∑m(−1)i⋅Cmi⋅e(m−2i)xj=0∑c−mCc−mj⋅e(m−c−2j)x
G(x)=2−c⋅Ccmi=0∑mj=0∑c−m(−1)i⋅Cmi⋅Cc−mj⋅e(c−2i−2j)x我们把上面的
e(c−2i−2j)x暴力展开:
G(x)=2−c⋅Ccmi=0∑mj=0∑c−m(−1)i⋅Cmi⋅Cc−mj⋅k=0∑∞k!((c−2i−2j)x)k那么我们就可以暴力求第
n项的系数
an:
an=2−c⋅Ccmi=0∑mj=0∑c−m(−1)i⋅Cmi⋅Cc−mj⋅n!((c−2i−2j)x)n所以答案为:
cnan⋅n!具体计算时,我们可以把答案的两个数乘到柿子的最后一项中,为了避免精度误差,我们最后在做除法,详见代码。
#include <cstdio>
#define db double
int read()
{
int num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=(num<<3)+(num<<1)+(c^48),c=getchar();
return num*flag;
}
int c,n,m;
db C[105][105];
db qkpow(db a,int b)
{
db res=1;
while(b>0)
{
if(b&1) res=res*a;
a=a*a;
b>>=1;
}
return res;
}
void init(int n)
{
C[0][0]=1;
for(int i=1;i<=n;i++)
{
C[i][0]=1;
for(int j=1;j<=i;j++)
C[i][j]=C[i-1][j-1]+C[i-1][j];
}
}
signed main()
{
init(100);
while(scanf("%d",&c) && c)
{
n=read();m=read();
if((n+m)%2 || m>n || m>c)
{
printf("0.000\n");
continue;
}
db ans=0;
for(int i=0;i<=m;i++)
for(int j=0;j<=c-m;j++)
ans+=((i&1)?-1:1)*C[m][i]*C[c-m][j]*qkpow((c-2*i-2*j)*1.0/c,n);
ans=ans*C[c][m]/qkpow(2,c);
printf("%.3f\n",ans);
}
}