[POJ-1322]Chocolate(生成函数)

题目

口袋里有 c c c种颜色的巧克力。从中随便取出一个。若桌上有与它颜色相同的巧克力,则两个都拿走;否则将它放在桌子上。求拿出 n n n个后桌子上剩 m m m个的概率。
数据范围: 1 ≤ c ≤ 100 , n , m ≤ 1000000 1≤c≤100,n,m≤1000000 1c100,n,m1000000

思路

  1. 易得:n,m奇偶性相同
  2. m ≤ c , n m≤c,n mc,n

设计

设有 a a a种巧克力取了奇数次,则有 c − a c-a ca种取了偶数次。
考虑到,若是使用普通生成函数的话,因为结果有除掉 k ! k! k!,所以是不好做的,这个时候,我们就选择使用指数型生成函数(EGF)。
奇数次的生成函数:
J ( x ) = x 1 ! + x 3 3 ! + x 5 5 ! + . . . J(x)=\frac{x}{1!}+\frac{x^3}{3!}+\frac{x^5}{5!}+... J(x)=1!x+3!x3+5!x5+...
偶数次的生成函数:
O ( x ) = 1 + x 2 2 ! + x 4 4 ! + . . . O(x)=1+\frac{x^2}{2!}+\frac{x^4}{4!}+... O(x)=1+2!x2+4!x4+...
设答案多项式为 H ( x ) H(x) H(x),有:
H ( x ) = C c a × J ( x ) a × O ( x ) c − a H(x)=C_{c}^{a}\times J(x)^a\times O(x)^{c-a} H(x)=Cca×J(x)a×O(x)ca
H ( x ) H(x) H(x)的第 n n n项前的系数就是合法的组合的方案数

转化

f ( x ) = e x f(x)=e^x f(x)=ex,对 f ( x ) f(x) f(x)在零点处进行泰勒展开。
f ( x ) = f ( x 0 ) + f ′ ( 0 ) 1 ! x + f ′ ′ ( 0 ) 2 ! x 2 + . . . f(x)=f(x_0)+\frac{f'(0)}{1!}x+\frac{f''(0)}{2!}x^2+... f(x)=f(x0)+1!f(0)x+2!f(0)x2+...
因为 e x = e ′ x e^x=e'^x ex=ex
所以 f ( x ) = f ′ ( x ) f(x)=f'(x) f(x)=f(x)
上式可化为
f ( x ) = 1 + x 1 ! + x 2 2 ! + x 3 3 ! + x 4 4 ! + . . . f(x)=1+\frac{x}{1!}+\frac{x^2}{2!}+\frac{x^3}{3!}+\frac{x^4}{4!}+... f(x)=1+1!x+2!x2+3!x3+4!x4+...
f ( − x ) = 1 − x 1 ! + x 2 2 ! − x 3 3 ! + x 4 4 ! + . . . f(-x)=1-\frac{x}{1!}+\frac{x^2}{2!}-\frac{x^3}{3!}+\frac{x^4}{4!}+... f(x)=11!x+2!x23!x3+4!x4+...
所以
e x = 1 + x 1 ! + x 2 2 ! + x 3 3 ! + x 4 4 ! + . . . e^x=1+\frac{x}{1!}+\frac{x^2}{2!}+\frac{x^3}{3!}+\frac{x^4}{4!}+... ex=1+1!x+2!x2+3!x3+4!x4+...
e − x = 1 − x 1 ! + x 2 2 ! − x 3 3 ! + x 4 4 ! + . . . e^{-x}=1-\frac{x}{1!}+\frac{x^2}{2!}-\frac{x^3}{3!}+\frac{x^4}{4!}+... ex=11!x+2!x23!x3+4!x4+...
e x − e − x = 2 x 1 ! + 2 x 3 3 ! + . . . 2 x 5 5 ! e^x-e^{-x}=2\frac{x}{1!}+2\frac{x^3}{3!}+...2\frac{x^5}{5!} exex=21!x+23!x3+...25!x5
e x + e − x = 2 + 2 x 2 2 ! + 2 x 4 4 ! + . . . e^x+e^{-x}=2+2\frac{x^2}{2!}+2\frac{x^4}{4!}+... ex+ex=2+22!x2+24!x4+...
所以奇数次的生成函数的闭形式为:
e x − e − x 2 \frac{e^x-e^{-x}}{2} 2exex
偶数次的生成函数的闭形式为:
e x + e − x 2 \frac{e^x+e^{-x}}{2} 2ex+ex

化简

由上可得:
H ( x ) = C c a × J ( x ) a × O ( x ) c − a = ( e x − e − x 2 ) a × ( e x + e − x 2 ) c − a H(x)=C_{c}^{a}\times J(x)^a\times O(x)^{c-a}=(\frac{e^x-e^{-x}}{2})^a\times (\frac{e^x+e^{-x}}{2})^{c-a} H(x)=Cca×J(x)a×O(x)ca=(2exex)a×(2ex+ex)ca
进行二项式展开:
H ( x ) = 2 − c × C c a × ∑ i = 0 a − 1 i × C a i × e a − 2 i x × ∑ j = 0 c − a C c − m j × e c − a − 2 j H(x)=2^{-c}\times C_{c}^{a}\times \sum_{i=0}^{a}{-1}^i\times C_{a}^{i}\times e^{a-2i}x\times \sum_{j=0}^{c-a}C_{c-m}^{j}\times e^{c-a-2j} H(x)=2c×Cca×i=0a1i×Cai×ea2ix×j=0caCcmj×eca2j
写成卷积:
H ( x ) = 2 − c × C c a × ∑ i = 0 a ∑ j = 0 c − a − 1 i × C a i × C c − m j × e c − 2 i − 2 j x H(x)=2^{-c}\times C_{c}^{a}\times \sum_{i=0}^{a}\sum_{j=0}^{c-a}{-1}^i\times C_{a}^{i}\times C_{c-m}^{j}\times e^{c-2i-2j}x H(x)=2c×Cca×i=0aj=0ca1i×Cai×Ccmj×ec2i2jx
e e e换掉
H ( x ) = 2 − c × C c a × ∑ i = 0 a ∑ j = 0 c − a − 1 i × C a i × C c − m j × ∑ k = 0 + ∞ ( ( c − 2 i − 2 j ) x ) k k ! H(x)=2^{-c}\times C_{c}^{a}\times \sum_{i=0}^{a}\sum_{j=0}^{c-a}{-1}^i\times C_{a}^{i}\times C_{c-m}^{j}\times \sum_{k=0}^{+\infty}\frac{(({c-2i-2j})x)^k}{k!} H(x)=2c×Cca×i=0aj=0ca1i×Cai×Ccmj×k=0+k!((c2i2j)x)k
所以
h n = 2 − c × C c a × ∑ i = 0 a ∑ j = 0 c − a − 1 i × C a i × C c − m j × ( c − 2 i − 2 j ) n n ! h_n=2^{-c}\times C_{c}^{a}\times \sum_{i=0}^{a}\sum_{j=0}^{c-a}{-1}^i\times C_{a}^{i}\times C_{c-m}^{j}\times \frac{(c-2i-2j)^n}{n!} hn=2c×Cca×i=0aj=0ca1i×Cai×Ccmj×n!(c2i2j)n

得到答案

上面的 h n h_n hn是合法的组合的方案数,因为颜色是有顺序的,所以还要乘上一个 n ! n! n!。而总方案数为 c n c^n cn
所以最后的 A n s Ans Ans为:
h n ∗ n ! c n \frac{h_n*n!}{c^n} cnhnn!
因为 1 ≤ c ≤ 100 1≤c≤100 1c100, 2 c 2^c 2c会乘爆,只能用 d o u b l e double double乘一下,用精度换数值正确。
把除放在最后,避免精度误差。

Code:

#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define DB double
#define MAXN 105
#define LL long long
#define Int register int
using namespace std;
inline int read()
{
	int x = 0, f = 1;
	char s = getchar();
	while (s < '0' || s > '9')
	{
		if (s == '-')
			f = -1;
		s = getchar();
	}
	while (s >= '0' && s <= '9')
	{
		x = (x << 3) + (x << 1) + (s ^ 48);
		s = getchar();
	}
	return x * f;
}
inline int Max(int x,int y)
{
	return x > y ? x : y;
}
inline int Min(int x,int y)
{
	return x < y ? x : y;
}
inline DB QuickPow(DB x,int y)
{
	DB Res = 1, temp = x;
	while ( y )
	{
		if (y & 1)
			Res *= temp;
		temp *= temp;
		y /= 2;
	}
	return Res;
}
DB C[MAXN][MAXN];
void Prepare()
{
	C[0][0] = 1;
	for (Int i = 1; i < MAXN; ++ i)
	{
		C[i][0] = 1;
		for (Int j = 1; j <= i; ++ j)
			C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
	}
	return ;
}
int main()
{
	int c, n, m;
	Prepare();
	while (~ scanf("%d %d %d", &c, &n, &m) && c)
	{
		if (m > c || m > n || (n - m) & 1)
		{
			printf("0.000\n");
			continue;
		}
		DB fuck = 0;
		for (Int i = 0; i <= m; ++ i)
			for (Int j = 0; j <= c - m; ++ j)
				fuck += ((i & 1) ? -1 : 1) * C[m][i] * C[c - m][j] * QuickPow((c - 2 * i - 2 * j) * 1.0 / c, n);
		fuck *= C[c][m];
		fuck /= QuickPow(2.0, c);
		printf("%.3lf\n", fuck);
	}
	return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值