zoukankan      html  css  js  c++  java
  • 「HAOI2018」染色

    题目链接:Click here

    Solution:

    看到恰好,首先考虑容斥,设(f[i])表示我们钦定(i)种颜色在序列中恰好出现了(S)次有多少种方案

    那么现在就有(i+1)个部分,把他看作是可重集的全排列,方案数即 ({n! over (S!)^i (n-Si)}) ,后面每个都可以选 ((m-i)) 种颜色

    那么(f[i])就是这样算的:

    [f[i]={mchoose i} imes {n! over (S!)^i (n-Si)!} imes (m-i)^{n-Si} ]

    现在我们来考虑容斥,(ans[i])表示恰好有(i)种颜色在序列中出现了恰好(S)次的方案,式子前乘的({jchoose i})代表钦定的颜色选取方案

    [ans[i]=sum_{j=i}^{lim} (-1)^{j-i}{jchoose i} f[j]\ ans[i]=sum_{j=i}^{lim} (-1)^{j-i}{j! over i! (j-i)!} f[j]\ ans[i] imes i!=sum_{j=i}^{lim} (-1)^{j-i}{j! over (j-i)!} f[j]\ ]

    这里的(lim=min(lfloor {n over S} floor , m)),我们令(A(x)=sum_{i=0} ^{lim} (-1)^i i! x^i),在令(A=reverse(A)),同时令(B(x)=sum_{i=0}^{lim} i!f[i] x^i)

    那么式子就转化成了这个样子:

    [ans[i] imes i!=sum_{j=i}^{lim} A_{lim+i-j} B_j ]

    这显然是个卷积的形式,于是我们直接上(NTT)即可

    Code:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int mod=1004535809;
    const int N=1e7+11;
    const int M=4e5+11;
    int n,m,s,ans,len=1,tim,lim,p[M];
    int fac[N],ifac[N],W[M],g[M],f[M];
    int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    int qpow(int x,int y){
        int re=1;
        while(y>0){
            if(y&1) re=re*x%mod;
            y>>=1;x=x*x%mod;
        }return re;
    }
    int C(int x,int y){
        if(x<y) return 0;
        return fac[x]*ifac[y]%mod*ifac[x-y]%mod;
    }
    void NTT(int *a,int flag){
        for(int i=0;i<len;i++)
            if(i<p[i]) swap(a[i],a[p[i]]);
        for(int l=2;l<=len;l<<=1){
            int wn=qpow(3,(mod-1)/l);
            if(flag==-1) wn=qpow(wn,mod-2);
            for(int st=0;st<len;st+=l){
                int w=1;
                for(int u=st;u<st+(l>>1);u++,w=w*wn%mod){
                    int x=a[u],y=w*a[u+(l>>1)]%mod;
                    a[u]=(x+y)%mod;a[u+(l>>1)]=(x+mod-y)%mod;
                }
            }
        }
    }
    signed main(){
        n=read(),m=read(),s=read();
        for(int i=0;i<=m;i++) W[i]=read();
        lim=min(n/s,m);++lim;
        while(len<(lim<<1)) len<<=1,++tim;
        --lim;
        for(int i=0;i<len;i++)
            p[i]=(p[i>>1]>>1)|((i&1)<<(tim-1));
        fac[0]=1;ifac[0]=1;
        for(int i=1;i<=max(len,max(n,m));i++) fac[i]=fac[i-1]*i%mod;
        ifac[max(len,max(n,m))]=qpow(fac[max(len,max(n,m))],mod-2);
        for(int i=max(len,max(n,m))-1;i;i--) ifac[i]=ifac[i+1]*(i+1)%mod;
        for(int i=0;i<=lim;i++){
            int inv=qpow(fac[s],i);
            inv=qpow(inv,mod-2);
            f[i]=C(m,i)*fac[n]%mod;
            f[i]=f[i]*inv%mod*ifac[n-s*i]%mod;
            f[i]=f[i]*qpow(m-i,n-s*i)%mod;
        }
        for(int i=0;i<=lim;i++) f[i]=f[i]*fac[i]%mod;
        for(int i=0;i<=lim;i++) g[lim-i]=(((i&1)?-1:1)*ifac[i]+mod)%mod;
        NTT(f,1);NTT(g,1);
        for(int i=0;i<=len;i++) f[i]=f[i]*g[i]%mod;
        NTT(f,-1);int invL=qpow(len,mod-2);
        for(int i=0;i<=len;i++) f[i]=f[i]*invL%mod;
        for(int i=0;i<=m;i++) ans=(ans+(f[lim+i]*ifac[i]%mod*W[i]%mod))%mod;
        printf("%lld
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    了解HTTP Header之User-Agent和HTTP协议的响应码
    怎样才算一个优秀的管理者
    ldpi、mdpi、hdpi、xhdpi、xxhdpi (无内容,待填)
    手把手教做小偷采集
    java中碰到无法解决的问题:无法访问类的getter访问器
    简单的加密解密处理
    Java中处理二进制移位
    Java中实现String.padLeft和String.padRight
    这短短几行代码价值一万
    从一篇文章中检查特定单词出现数量和第一次出现位置
  • 原文地址:https://www.cnblogs.com/NLDQY/p/12245139.html
Copyright © 2011-2022 走看看