• 生成函数(EGF)练习, UVA1305 Chocolate 题解


    洛谷地址,但不建议在UVA上测,建议去POJ

    题意描述

    有一袋无限多个的球,c种颜色,每次拿出一个放在桌上,若拿出的球与桌上的一个球颜色相同,就把两个球都丢进垃圾桶
    拿n次,求最后桌上剩下m个球的概率

    题解

    仔细考虑,会发现m不能大于c、n的任何一个,所以m小于100
    可以想到,若一个颜色的球被拿出过奇数次,这个颜色就会对答案做出贡献,所以我们需要m种颜色被拿出m次,剩下的拿出偶数次
    每个颜色独立等概率,所以分开计算
    设一个颜色球被拿出奇数次的概率的生成函数为(G(x)=sum{frac{1}{i!}*x^i})(i为奇数)
    同样的(F(x)=sum{frac{1}{i!}*x_i})(i为偶数)
    由于这题求的数是组合数(每个球都一样,所以不是排列),所以我们的生成函数是(EGF)(也就是要除以i!,想深入了解的可自行baidufirstsearch)
    然后我们想求的就是

    [ans=frac{C^{m}_{c}}{c^n}*G(x)^m*F(x)^{c-m}*n! ]

    然后为什么要乘上(n!)呢,我们考虑一个简化的小问题
    将3种颜色的球(各有a,b,c个)放成一排,答案是(C^{a}_{a+b+c}*C^{b}_{a+c}*C^{c}_{c})
    化简得(frac{(a+b+c)!}{a!*b!*c!})
    这里也就是这个道理了
    然后根据一个公式:(e^x=sum{frac{x_i}{i!}})(啊我不会证,建议按(LH)大佬说的,背下来)
    (F(x)=frac{e^x+e^{-x}}{2})(关于为什么是(e^x+e^{-x}),请将(-x)带入原多项式试试看)
    同理(G(x)=frac{e^x-e^{-x}}{2})
    那么我们就要求

    [(frac{e^x-e^{-x}}{2})^m*(frac{e^x+e^{-x}}{2})^{c-m} ]

    把分母提取出来,用快速幂直接算,分子由二项式定理展开

    [sum{(-1)^i*C^{i}_{m}*e^{i}*e^{-(m-i)}}*sum{C^{j}_{c-m}*e^{j}*e^{c-m-j}} ]

    化简

    [sum{sum{(-1)^i*C^{i}_{m}*C^{j}_{c-m}*e^{c-2*i-2*j}}} ]

    我们用上面那个我不会证的柿子再推回去

    [sum{sum{(-1)^i*C^{i}_{m}*C^{j}_{c-m}*sum{frac{(c-2*i-2*j)^k}{k!}*x^k}}} ]

    考虑生成函数的性质(或者是定义?),生成函数的系数就是问题的答案,所以我们需要的只有第n项
    也就是把k固定为n(如果看到这里懵逼了,建议休息一下,突然看到代入相信会把不少人吓一跳)
    所以柿子就变成了

    [sum{sum{(-1)^i*C^{i}_{m}*C^{j}_{c-m}*frac{(c-2*i-2*j)^n}{n!}*x^n}} ]

    乘上刚刚说的n!,就把n!消掉了
    最终柿子为

    [ans=frac{C^{m}_{c}}{c^n*2^c}*sum{sum{(-1)^i*C^{i}_{m}*C^{j}_{c-m}*frac{(c-2*i-2*j)^n}{n!}}} ]

    由于c、m都比较小,所以时间复杂度很优秀
    然后上代码,由于UVA恶臭,没有在洛谷上AC,只在poj上过了,代码也因为瞎改搞得比较丑,参考就好

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll double
    #define int long long
    using namespace std;
    int n,m,c;
    ll ans,C[105][105];
    
    static inline ll ksm(ll x,int k){
        ll tmp=1,X=x;
        while(k){
            if((k%2)==1)tmp=tmp*X;
            X=X*X,k/=2;
        }
        return tmp;
    }
    
    signed main(){
        C[0][0]=1.0;
        for(int i=1;i<=103;i++){
            C[i][0]=1.0;
            for(int j=1;j<=i;j++)C[i][j]=C[i-1][j-1]+C[i-1][j];
        }
        while(cin>>c){
            if(!c)break;
            scanf("%lld%lld",&n,&m),ans=0.0;
            if(m>c||m>n||(n-m)%2==1){
                printf("0.000
    ");
                continue;
            }
            for(int i=0;i<=m;i++){
                for(int j=0;j<=c-m;j++){
                    ans+=((i&1)==1?-1:1)*C[m][i]*C[c-m][j]*ksm((c-2*i-2*j)*1.0/c,n);
                }
            }
            ans=ans*C[c][m];
            ans/=ksm(2.0,c);
            printf("%.3lf
    ",ans);
        }
    }
    
  • 相关阅读:
    (转载)Rime输入法—鼠须管(Squirrel)词库添加及配置
    (转载)Windows下小狼毫输入法(Rime)的安装与配置(含导入搜狗词库)
    (转载)WinCC 卸载后 Simatic Shell 的删除
    (转载)西门子PLC学习笔记十五-(数据块及数据访问方式)
    (转载)一张表搞清楚西门子S7系列标准DB块与优化DB块
    (转载)Navicat Premium 12.1.16.0安装与激活
    (转载)MySQl数据库-批量添加数据的两种方法
    (转载)用C#实现MySQL建库及建表
    设置MYSQL数据库编码为UTF-8
    [设计模式]工厂方法模式(Factory Method)
  • 原文地址:https://www.cnblogs.com/caijiLYC/p/14344838.html
Copyright © 2020-2023  润新知