Chocolate

一、题目

题目描述
一个口袋中装有巧克力,巧克力的颜色有 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 1c100,1n,m1000000

二、解法

发现最后还在桌面上的巧克力一定是出现奇数次的,我们把奇数和偶数的情况分别表示成母函数(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 ex1=x x x x趋近于 0 0 0),我们先设 y = e x − 1 y=e^x-1 y=ex1把两边取对数, 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 ex1=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+Δxex=Δxex(eΔx1)=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)(xx0)+2!f(x0)(xx0)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)=2exex f 1 ( x ) = e x + e − x 2 f_1(x)=\frac{e^x+e^{-x}}{2} f1(x)=2ex+ex所以我们要取出 m m m个颜色使它为奇数,取出 c − m c-m cm个颜色使它为偶数,把所有颜色整合后的母函数表示出来:
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(2exex)m(2ex+ex)cm 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)=2cCcm(exex)m(ex+ex)cm 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)=2cCcmi=0m(1)iCmie(m2i)xj=0cmCcmje(mc2j)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)=2cCcmi=0mj=0cm(1)iCmiCcmje(c2i2j)x我们把上面的 e ( c − 2 i − 2 j ) x e^{(c-2i-2j)x} e(c2i2j)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)=2cCcmi=0mj=0cm(1)iCmiCcmjk=0k!((c2i2j)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=2cCcmi=0mj=0cm(1)iCmiCcmjn!((c2i2j)x)n所以答案为:
a n ⋅ n ! c n \frac{a_n\cdot n!}{c^n} cnann!具体计算时,我们可以把答案的两个数乘到柿子的最后一项中,为了避免精度误差,我们最后在做除法,详见代码。

#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);
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值