zoukankan      html  css  js  c++  java
  • UOJ #449. 【集训队作业2018】喂鸽子

    http://uoj.ac/problem/449

    题解

    warning:式子全都抄的题解。

    我们可以先套一层(min-max)反演。

    [ans=sum_{i=1}^n (-1)^{i-1}inom{n}{i}g_i ]

    那么(g_i)就表示喂饱(i)只鸽子中至少一只的期望步数。

    [g_i=sum_{igeq 1}i*P(x=i) ]

    [=sum_{igeq 1}P(xgeq i) ]

    然后考虑设计一个(dp),设(f(sum,cnt))表示喂(sum)只鸽子,喂了(cnt)次,都没有喂饱的概率。

    [g_i=sum_{jgeq 1}sum_{s=0}^{i-1}inom{i-1}{s}f(i,s)(frac{n-i}{n}) ^{i-1-s} ]

    考虑枚举有一次喂食喂到了(i)只鸽子中,根据鸽巢原理,

    [g_i=sum_{s=0}^{i(k-1)}f(i,s)sum_{j geq 0}inom{s+j}{s}(frac{n-i}{n})^j ]

    有一个不知道为什么的东西:

    [(frac{1}{1-x})^k=sum_{igeq 0}inom{i+k-1}{k-1}x^i ]

    那么:

    [sum_{jgeq 0}inom{s+t}{t}(frac{n-c}{n})^t=(frac{1}{1-frac{n-c}{n}})^{s+1}=(frac{n}{c})^{s+1} ]

    [g_i=sum_{s=0}^{i(k-1)}f(i,s)(frac{n}{c})^{s+1} ]

    [f(c,s)=sum_{i=0}^{min(s,k-1)}inom{s}{i}frac{1}{n^i}f(c-1,s-i) ]

    [frac{f(c,s)}{s!}=sum_{i=0}^{min(s,k-1)}frac{1}{n^ii!}frac{f(c-1,s-i)}{(s-i)!} ]

    然后就可以(NTT)算了。

    代码

    #include<bits/stdc++.h>
    #define N 52
    #define K 1002
    #define M 68002
    using namespace std;
    typedef long long ll;
    int n,k,rev[M];
    ll dp[N][M],inv[M],jie[M],ni[M],ans,g[N];
    const int G=3;
    const int Gi=332748118;
    const int mod=998244353;
    inline ll rd(){
    	ll x=0;char c=getchar();bool f=0;
    	while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f?-x:x;
    }
    inline ll power(ll x,ll y){
    	ll ans=1;
    	while(y){
    		if(y&1)ans=ans*x%mod;
    		x=x*x%mod;
    		y>>=1;
    	}
    	return ans;
    }
    inline void MOD(ll &x){x=x>=mod?x-mod:x;}
    inline ll C(int n,int m){return jie[n]*ni[m]%mod*ni[n-m]%mod;}
    inline void NTT(ll *a,int l,int tag){
        for(int i=1;i<l;++i)if(i>rev[i])swap(a[i],a[rev[i]]);
        for(int i=1;i<l;i<<=1){
            ll wn=power(tag?G:Gi,(mod-1)/(i<<1));
            for(int j=0;j<l;j+=(i<<1)){
                ll w=1;
                for(int k=0;k<i;++k,w=w*wn%mod){
                    ll x=a[j+k],y=a[i+j+k]*w%mod;
                    MOD(a[j+k]=x+y);MOD(a[i+j+k]=x-y+mod);
                }
            }
        }
        if(!tag){
            ll ny=power(l,mod-2);
            for(int i=0;i<l;++i)a[i]=a[i]*ny%mod;
        }
    }
    inline void prework(int n){
    	jie[0]=1;
    	for(int i=1;i<=n;++i)jie[i]=jie[i-1]*i%mod;
    	ni[n]=power(jie[n],mod-2);
        for(int i=n-1;i>=0;--i)ni[i]=ni[i+1]*(i+1)%mod;
    }
    int main(){
    	n=rd();k=rd();
    	prework(n*k);
    	for(int i=0;i<k;++i)inv[i]=power(power(n,i),mod-2)*ni[i]%mod;
    	int maxn=n*(k-1);
        dp[0][0]=1;
        int l=1,L=0;
        while(l<=maxn)l<<=1,L++;
        for(int i=1;i<l;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(L-1));
        NTT(dp[0],l,1);NTT(inv,l,1);
        for(int i=1;i<=n;++i){
          for(int j=0;j<l;++j)dp[i][j]=dp[i-1][j]*inv[j]%mod;
        }
        for(int i=1;i<=n;++i){
        	NTT(dp[i],l,0);
        	int x=i*(k-1);
        	ll nii=1ll*n*power(i,mod-2)%mod,num=1;
        	for(int j=0;j<=x;++j){
        		dp[i][j]=dp[i][j]*jie[j]%mod;
        		num=num*nii%mod;
        		MOD(g[i]+=dp[i][j]*num%mod);
        	}
        }
        for(int i=1;i<=n;++i){
          if(i&1)MOD(ans+=C(n,i)*g[i]%mod);
          else MOD(ans=ans-C(n,i)*g[i]%mod+mod);
        }
        cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    新文章new图标
    3.6SiteFactory专业版,顶部导航的最后一个栏目向下移位的解决办法
    http://goodboy5264.blog.163.com/
    提升你网站水平的 jQuery 插件推荐
    如何把导航条做成sitefactory政府版的样子实现动态读取子栏目显示
    好的链接
    2011年度最佳jQuery插件
    asp中日期时间函数介绍
    若干设计模式学习
    多线程学习
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/11029673.html
Copyright © 2011-2022 走看看