一、题目
题目描述
一个口袋中装有巧克力,巧克力的颜色有
c
c
c种。现从口袋中取出一个巧克力,若取出的巧克力与桌上某一已有巧克力颜色相同,则将两个巧克力都取走,否则将取出的巧克力放在桌上。设从口袋中取出每种颜色的巧克力的概率均等。求取出
n
n
n个巧克力后桌面上剩余
m
m
m个巧克力的概率。
数据范围
1
≤
c
≤
100
,
1
≤
n
,
m
≤
1000000
1\leq c\leq 100,1\leq n,m\leq 1000000
1≤c≤100,1≤n,m≤1000000
二、解法
发现最后还在桌面上的巧克力一定是出现奇数次的,我们把奇数和偶数的情况分别表示成母函数(0奇1偶),因为我们还需要考虑排列,相同颜色的排列必须要消去,所以我们把这个任务交给母函数的系数,最后在乘上
n
!
n!
n!即可:
f
0
(
x
)
=
x
1
!
+
x
3
3
!
+
x
5
5
!
+
.
.
.
.
.
f_0(x)=\frac{x}{1!}+\frac{x^3}{3!}+\frac{x^5}{5!}+.....
f0(x)=1!x+3!x3+5!x5+.....
f
1
(
x
)
=
1
0
!
+
x
2
2
!
+
x
4
4
!
+
.
.
.
.
.
f_1(x)=\frac{1}{0!}+\frac{x^2}{2!}+\frac{x^4}{4!}+.....
f1(x)=0!1+2!x2+4!x4+.....我们考虑用自然底数
e
e
e表示它们的闭形式,先给出一个结论,
e
x
=
(
1
+
1
n
)
n
x
=
1
+
x
1
!
+
x
2
2
!
+
.
.
.
.
e^x=(1+\frac{1}{n})^{nx}=1+\frac{x}{1!}+\frac{x^2}{2!}+....
ex=(1+n1)nx=1+1!x+2!x2+....下面给出证明:
结论一: e x e^x ex等于 e x e^x ex的求导
先证明等价无穷小,即 e x − 1 = x e^x-1=x ex−1=x( x x x趋近于 0 0 0),我们先设 y = e x − 1 y=e^x-1 y=ex−1把两边取对数, x = ln ( y + 1 ) x=\ln(y+1) x=ln(y+1),因为 x x x趋近于 0 0 0,所以 ln ( y + 1 ) \ln(y+1) ln(y+1)趋近于 1 1 1,推出 y y y趋近于 0 0 0,所以 e x − 1 = x e^x-1=x ex−1=x
然后我们暴力对
e
x
e^x
ex 求导:
e
x
+
Δ
x
−
e
x
Δ
x
=
e
x
⋅
(
e
Δ
x
−
1
)
Δ
x
=
e
x
\frac{e^{x+\Delta x}-e^x}{\Delta x}=\frac{e^x\cdot(e^{\Delta x}-1)}{\Delta x}=e^x
Δxex+Δx−ex=Δxex⋅(eΔx−1)=ex运用了等价无穷小,问题得证。
结论二:泰勒展开很香
我们把
e
x
e^x
ex在
x
=
0
x=0
x=0出泰勒展开,得到(注,
f
(
x
)
=
e
x
f(x)=e^x
f(x)=ex):
f
(
x
)
=
f
(
x
0
)
+
f
′
(
x
0
)
1
!
(
x
−
x
0
)
+
f
′
′
(
x
0
)
2
!
(
x
−
x
0
)
2
.
.
.
.
f(x)=f(x_0)+\frac{f'(x_0)}{1!}(x-x_0)+\frac{f''(x_0)}{2!}(x-x_0)^2....
f(x)=f(x0)+1!f′(x0)(x−x0)+2!f′′(x0)(x−x0)2....
f
(
x
)
=
1
+
x
1
!
+
x
2
2
!
+
x
3
3
!
+
.
.
.
.
.
.
f(x)=1+\frac{x}{1!}+\frac{x^2}{2!}+\frac{x^3}{3!}+......
f(x)=1+1!x+2!x2+3!x3+......结合了结论一,故原等式成立。
然后我们可以把奇数和偶数的母函数用
e
x
e^x
ex表示出来:
f
0
(
x
)
=
e
x
−
e
−
x
2
f_0(x)=\frac{e^x-e^{-x}}{2}
f0(x)=2ex−e−x
f
1
(
x
)
=
e
x
+
e
−
x
2
f_1(x)=\frac{e^x+e^{-x}}{2}
f1(x)=2ex+e−x所以我们要取出
m
m
m个颜色使它为奇数,取出
c
−
m
c-m
c−m个颜色使它为偶数,把所有颜色整合后的母函数表示出来:
G
(
x
)
=
C
c
m
⋅
(
e
x
−
e
−
x
2
)
m
⋅
(
e
x
+
e
−
x
2
)
c
−
m
G(x)=C_c^m\cdot (\frac{e^x-e^{-x}}{2})^m\cdot(\frac{e^x+e^{-x}}{2})^{c-m}
G(x)=Ccm⋅(2ex−e−x)m⋅(2ex+e−x)c−m
G
(
x
)
=
2
−
c
⋅
C
c
m
⋅
(
e
x
−
e
−
x
)
m
⋅
(
e
x
+
e
−
x
)
c
−
m
G(x)=2^{-c}\cdot C_c^m\cdot (e^x-e^{-x})^m\cdot (e^x+e^{-x})^{c-m}
G(x)=2−c⋅Ccm⋅(ex−e−x)m⋅(ex+e−x)c−m
G
(
x
)
=
2
−
c
⋅
C
c
m
∑
i
=
0
m
(
−
1
)
i
⋅
C
m
i
⋅
e
(
m
−
2
i
)
x
∑
j
=
0
c
−
m
C
c
−
m
j
⋅
e
(
m
−
c
−
2
j
)
x
G(x)=2^{-c}\cdot C_c^m\sum_{i=0}^m (-1)^i\cdot C_m^i\cdot e^{(m-2i)x}\sum_{j=0}^{c-m}C_{c-m}^j \cdot e^{(m-c-2j)x}
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
⋅
C
c
m
∑
i
=
0
m
∑
j
=
0
c
−
m
(
−
1
)
i
⋅
C
m
i
⋅
C
c
−
m
j
⋅
e
(
c
−
2
i
−
2
j
)
x
G(x)=2^{-c}\cdot C_c^m\sum_{i=0}^m\sum_{j=0}^{c-m}(-1)^i\cdot C_m^i\cdot C_{c-m}^j\cdot e^{(c-2i-2j)x}
G(x)=2−c⋅Ccmi=0∑mj=0∑c−m(−1)i⋅Cmi⋅Cc−mj⋅e(c−2i−2j)x我们把上面的
e
(
c
−
2
i
−
2
j
)
x
e^{(c-2i-2j)x}
e(c−2i−2j)x暴力展开:
G
(
x
)
=
2
−
c
⋅
C
c
m
∑
i
=
0
m
∑
j
=
0
c
−
m
(
−
1
)
i
⋅
C
m
i
⋅
C
c
−
m
j
⋅
∑
k
=
0
∞
(
(
c
−
2
i
−
2
j
)
x
)
k
k
!
G(x)=2^{-c}\cdot C_c^m\sum_{i=0}^m\sum_{j=0}^{c-m}(-1)^i\cdot C_m^i\cdot C_{c-m}^j\cdot \sum_{k=0}^\infty \frac{((c-2i-2j)x)^k}{k!}
G(x)=2−c⋅Ccmi=0∑mj=0∑c−m(−1)i⋅Cmi⋅Cc−mj⋅k=0∑∞k!((c−2i−2j)x)k那么我们就可以暴力求第
n
n
n项的系数
a
n
a_n
an:
a
n
=
2
−
c
⋅
C
c
m
∑
i
=
0
m
∑
j
=
0
c
−
m
(
−
1
)
i
⋅
C
m
i
⋅
C
c
−
m
j
⋅
(
(
c
−
2
i
−
2
j
)
x
)
n
n
!
a_n=2^{-c}\cdot C_c^m\sum_{i=0}^m\sum_{j=0}^{c-m}(-1)^i\cdot C_m^i\cdot C_{c-m}^j\cdot \frac{((c-2i-2j)x)^n}{n!}
an=2−c⋅Ccmi=0∑mj=0∑c−m(−1)i⋅Cmi⋅Cc−mj⋅n!((c−2i−2j)x)n所以答案为:
a
n
⋅
n
!
c
n
\frac{a_n\cdot n!}{c^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);
}
}