题目大意:
一共有 c c c种糖果,取 n n n次,每次取到糖果种类都是等概率的,求有 m m m种糖果个数为奇数个的概率。
思路:
直接概率DP时间复杂度太高,卡常数也不太好卡。
将每次取出来的糖果看成是一个带有重复元素的排列,直接计算复合条件的排列数量。
考虑符合条件的最后的序列的考虑EGF(指数型生成函数),可得出现次数为偶数次的糖果的生成函数为:
F
0
(
x
)
=
∑
i
=
0
∞
x
2
i
(
2
i
)
!
=
e
x
+
e
−
x
2
F_0(x)=\sum_{i=0}^{\infty}\frac{x^{2i}}{(2i)!}=\frac{e^x+e^{-x}}{2}
F0(x)=i=0∑∞(2i)!x2i=2ex+e−x
出现奇数次的糖果的生成函数为:
F
1
(
x
)
=
∑
i
=
0
∞
x
2
i
+
1
(
2
i
+
1
)
!
=
e
x
−
e
−
x
2
F_1(x)=\sum_{i=0}^{\infty}\frac{x^{2i+1}}{(2i+1)!}=\frac{e^x-e^{-x}}{2}
F1(x)=i=0∑∞(2i+1)!x2i+1=2ex−e−x
可以得到最后的答案的生成函数为:
F
1
m
(
x
)
×
F
0
c
−
m
(
x
)
=
(
e
x
−
e
−
x
2
)
m
×
(
e
x
+
e
−
x
2
)
c
−
m
F_1^{m}(x)\times F_0^{c-m}(x)=(\frac{e^x-e^{-x}}{2})^m\times(\frac{e^x+e^{-x}}{2})^{c-m}
F1m(x)×F0c−m(x)=(2ex−e−x)m×(2ex+e−x)c−m
将
e
x
e^x
ex看成是一个整体,然后两边分别二项式展开之后做卷积,然后再将
e
x
e^x
ex展开即可得到第
n
n
n项系数。
G
(
x
)
=
2
−
c
×
∑
i
=
0
m
(
−
1
)
i
(
m
i
)
×
e
(
m
−
2
i
)
x
×
∑
j
=
0
c
−
m
(
c
−
m
j
)
×
e
(
2
j
−
c
+
m
)
x
=
2
(
−
c
)
×
∑
i
=
0
m
∑
j
=
0
c
−
m
(
−
1
)
i
(
m
i
)
(
c
−
m
j
)
×
e
(
2
m
−
2
i
+
2
j
−
c
)
x
=
2
(
−
c
)
×
∑
i
=
0
m
∑
j
=
0
c
−
m
(
−
1
)
i
(
m
i
)
(
c
−
m
j
)
×
∑
k
=
0
∞
(
(
2
m
−
2
i
+
2
j
−
c
)
x
)
k
k
!
\begin{aligned} G(x)&=2^{-c}\times \sum_{i=0}^{m}(-1)^i{m\choose i}\times e^{(m-2i)x}\times \sum_{j=0}^{c-m}{c-m\choose j}\times e^{(2j-c+m)x}\\ &=2^{(-c)}\times \sum_{i=0}^{m}\sum_{j=0}^{c-m}(-1)^i{m\choose i}{c-m\choose j}\times e^{(2m-2i+2j-c)x}\\ &=2^{(-c)}\times \sum_{i=0}^{m}\sum_{j=0}^{c-m}(-1)^i{m\choose i}{c-m\choose j}\times \sum_{k=0}^{\infty}\frac{((2m-2i+2j-c)x)^k}{k!} \end{aligned}
G(x)=2−c×i=0∑m(−1)i(im)×e(m−2i)x×j=0∑c−m(jc−m)×e(2j−c+m)x=2(−c)×i=0∑mj=0∑c−m(−1)i(im)(jc−m)×e(2m−2i+2j−c)x=2(−c)×i=0∑mj=0∑c−m(−1)i(im)(jc−m)×k=0∑∞k!((2m−2i+2j−c)x)k
设第
n
n
n项的系数为
a
n
a_n
an,最后的答案为:
a
n
×
(
c
m
)
×
n
!
2
c
×
c
n
\frac{a_n\times{c\choose m}\times n!}{2^c\times c^n}
2c×cnan×(mc)×n!
垃圾poj
坑点:
如果用实数类去计算,中间过程可能会爆精度,特别是中间的快速幂,建议将最后分母的那个
c
m
c^m
cm移到系数的快速幂里面,这样会让中间过程的数值小一些。
好像用不了%lf,直接用%f即可。
交C++好像过不了。
/*=======================================
* Author : ylsoi
* Time : 2019.2.1
* Problem : Chocolate
* E-mail : ylsoi@foxmail.com
* ====================================*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef long long ll;
using namespace std;
void File(){
freopen("poj1322.in","r",stdin);
freopen("poj1322.out","w",stdout);
}
template<typename T>void read(T &_){
_=0; T fl=1; char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fl=-1;
for(;isdigit(ch);ch=getchar())_=(_<<1)+(_<<3)+(ch^'0');
_*=fl;
}
const int maxn=1e6+10;
const int maxc=200+10;
int c,n,m;
double C[maxc][maxc],ans;
double qpow(double x,int y){
double ret=1;
while(y){
if(y&1)ret=ret*x;
x=x*x;
y>>=1;
}
return ret;
}
void init(){
C[0][0]=1;
REP(i,1,200){
C[i][0]=1;
REP(j,1,i)C[i][j]=C[i-1][j-1]+C[i-1][j];
}
}
int main(){
File();
init();
while(~scanf("%d%d%d",&c,&n,&m)){
if(!c)break;
ans=0;
if(m>c || m>n || (n-m)%2){
printf("0.000\n");
continue;
}
REP(i,0,m)REP(j,0,c-m)
ans+=(i%2 ? -1 : 1)*C[m][i]*C[c-m][j]*qpow((2*m-2*i+2*j-c)*1.0/c,n);
ans=ans*C[c][m]/qpow(2,c);
printf("%.3f\n",ans);
}
return 0;
}