习题:Chocolate(生成函数)

题目

传送门

思路

每一种取多少,最后还需要达到一个固定的值,比较容易联想到生成函数上面去

对于一个颜色

如果这个颜色是选奇数个

\(F(x)=\sum_{i=0}^{\infty}x^{2*i+1}\)

如果是偶数个

\(G(x)=\sum_{i=0}^{\infty}x^{2i}\)

但是问题在于如果你将他们卷起来

因为顺序的问题

答案并不是某一项的系数。

我们实际上要卷起来的应该是

如果是奇数个

\(F(x)=\sum_{i=0}^{\infty}\frac{x^{2i+1}}{(2i+1)!}\)

如果是偶数个

\(G(x)=\sum_{i=0}^{\infty}\frac{x^{2i}}{(2i)!}\)

之后卷起来的\(x^n\)的系数就是答案

接着我们考虑如何将\(F\)\(G\)转换成为闭形式

我们首先考虑最简单的形式,

\(A(x)=\sum_{i=0}^{\infty}\frac{x^i}{i!}\)

这不就是\(e^x\)

解释下原因

我们设\(B(x)=e^x\)

\(B\)进行泰勒展开

\(B(x)=\sum_{i=0}^{\infty}(\frac{B^{'(i个)}(x_0)}{i!}*(x-x_0)^i)\)

我们取\(x_0=0\)

\(B(x)=\sum_{i=0}^{\infty}(\frac{B^{'(i个)}(0)}{i!}*(x-x_0)^i)\)

由于e的性质

\(B'=B\)

所以

\(B(x)=\sum_{i=0}^{\infty}\frac{x^i}{i!}=A(x)\)

我们有了这个东西,我们再来考虑怎样构造

如果是奇数个,其实就是没有\(x^{2i}\)

则就是\(F(x)=\frac{e^x-e^{-x}}{2}\)

对于\(G(x)\)的构造同理

\(G(x)=\frac{e^x+e^{-x}}{2}\)

我们要求的就是\(F^m(x)*G^{c-m}(x)\)\(x^n\)的系数

考虑用二项式定理大力展开

\(\begin{aligned}F^m(x)*G^{c-m}(x)&=(\frac{e^x-e^{-x}}{2})^m*(\frac{e^x+e^{-x}}{2})^{c-m}\\&=\frac{\sum_{k=0}^{m}(-1)^{k}C_{m}^{k}e^{(m-k)x}e^{-kx}}{2^m}*\frac{\sum_{k=0}^{c-m}C_{c-m}^{k}e^{(c-m-k)x}e^{-kx}}{2^{c-m}}\end{aligned}\)

分母可以直接用快速幂算,我们接着对分子进行进一步的化简

就是

\(\sum_{i=0}^{m}\sum_{j=0}^{c-m}(-1)^iC_m^iC_{c-m}^je^{(c-2i-2j)x}\)

我们再对e写成母函数的形式

\(\sum_{i=0}^{m}\sum_{j=0}^{c-m}(-1)^iC_m^iC_{c-m}^j\sum_{k=0}^{\infty}\frac{(c-2i-2j)^k}{k!}\)

因为对我们对于e的母函数形式有用的仅仅是第n项的系数

所以

\(\sum_{n=0}^{\infty}\frac{\sum_{i=0}^{m}\sum_{j=0}^{c-m}(-1)^iC_m^iC_{c-m}^{j}(c-2i-2j)^n}{n!}x^n\)

由于\(n!\)本身是有e转换成母函数的形式所出现的,所以\(n!\)是可以忽略的

但是我们要求的是概率,最后还需要除以一个\(c^n\)

还由于我们定义母函数的时候本身就没有考虑是那些糖果要选奇数个,所以还要选一个\(C_c^m\)

所以最后的答案是\(\frac{C_c^m}{2^cc^n}\sum_{i=0}^{m}\sum_{j=0}^{c-m}(-1)^iC_m^iC_{c-m}^j(c-2i-2j)^n\)

分析这个式子,就可以得到\(m\le c\)

所以总的时间复杂度为\(O(c^2*logn)\)

代码

#include<iostream>
#include<cstdio>
using namespace std;
double ans;
long long c,m,n;
double qkpow(long long a,long long b)
{
	if(b==0)
		return 1;
	if(b==1)
		return a;
	double t=qkpow(a,b/2);
	t=t*t;
	if(b%2==1)
		t=t*a;
	return t;
}
double C(long long n,long long m)
{
	double ret=1;
	for(int i=n;i>=n-m+1;i--)
	{
		ret=ret*i/(n-i+1);
	}
	return ret;
}
int main()
{
	while(cin>>c)
	{
		if(!c)
			break;
		ans=0;
		cin>>n>>m;
		if(m>c||m>n||(n-m)%2==1)
		{
			printf("0.000\n");
			continue;
		}
		for(int i=0;i<=m;i++)
		{
			for(int j=0;j<=c-m;j++)
			{
				ans+=qkpow(-1,i)*C(m,i)*C(c-m,j)*qkpow(c-2*i-2*j,n);
			}
		}
		ans=ans*C(c,m)/qkpow(2,c)/qkpow(c,n);
		printf("%.3lf\n",ans);
	}
	return 0;
}
posted @ 2019-12-26 21:00  loney_s  阅读(252)  评论(0)    收藏  举报