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 }

 

posted @ 2018-05-18 12:44  menhera  阅读(470)  评论(0编辑  收藏  举报