ZOJ1363 Chocolate 【生成函数】 【泰勒展开】
题目大意:
有c种不同的巧克力,每种无限个,意味着取出每种的几率每次为1/c。现在你需要取n次。然后将统计每种取出来的巧克力的数量。若为偶数则舍去,否则留下一个。问最后留下m个的概率是多少。
题目分析:
由于取出每种巧克力的概率始终相同,。不妨假设取出奇数个的巧克力正好是1~m,m+1则取出偶数次,然后求出这种情况的次数。最后答案乘以C(c,m)再除以c^n即可。由于可以取出相同的巧克力,所以采用指数型生成函数。
对于前m种,构造g(x)=x/1!+x^3/3!+x^5/5!.....=sinh(x),后面类似地构造出h(x)=cosh(x).答案就是sinh^m(x)*cosh^(c-m)(x)的n阶导数。
将sinh(x)和cosh(x)写出来。得到e^x-e^(-x)/2和e^x+e^(-x)/2.其中加减法优先于除法。带入原式就得到了(e^x-e^(-x)/2)^m(x)*(e^x+e^(-x)/2)^(c-m)(x).通过二项式定理展开,然后乘起来。最后对e^kx单独泰勒展开。
结果就是这些的和。值得注意的是这题会爆longlong,应该把过程取对数。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int c,n,m; 5 6 double C[150][150]; 7 double res[150][150]; 8 9 void work(){ 10 memset(res,0,sizeof(res)); 11 if(m > c){puts("0");return;} 12 int A = m,B = c-m; 13 double ans = 0; 14 for(int i=0;i<=B;i++){ 15 for(int j=0;j<=A;j++){ 16 int f = 1; 17 if(A-B+2*i-2*j < 0&&(n&1)) f *= -1; 18 if(j & 1) f *= -1; 19 res[i][j] = C[B][i]+C[A][j]+(double)n*log10(abs(A-B+2*i-2*j)); 20 res[i][j] -= (double)c*log10(2.0); 21 res[i][j] += C[c][m]; 22 res[i][j] -= (double)n*log10(c); 23 if(res[i][j] < -30) continue; 24 ans += f*pow(10,res[i][j]); 25 } 26 } 27 printf("%.3lf\n",ans+1e-8); 28 } 29 30 int main(){ 31 for(int i=1;i<=100;i++){ 32 for(int j=1;j<i;j++){ 33 C[i][j] = C[i][j-1]+log10(i-j+1)-log10(j); 34 } 35 } 36 do{ 37 scanf("%d",&c); 38 if(c == 0) break; 39 scanf("%d%d",&n,&m); 40 work(); 41 }while(true); 42 return 0; 43 }