BZOJ 5306: [Haoi2018] staining binomial inversion + NTT

 Given a sequence of length n-$ $, each location can be colored $ m $ a certain kind of colors. If just emerged times $ s $ $ k $ color species, will produce $ W_ the value $ {k}. demand for all possible staining protocol, and results obtained value modulo $ $ 1,004,535,809.

Provided $ lim = min (m, \ frac {n} {s}) $, i.e. the maximum possible kinds of colors appear.
According to routine, so $ f [i] $ denotes Imperial $ I $ Lengths of $ s $ appears program number, $ g [i] $ represents just $ i number appearing scheme $ species.
$ F [K] = \ Binom {m} {K} \ FRAC {n-!} {(n--KS)! (S! ) ^ k} (mk) ^ {n-ks} $
composition significance is selected from $ KS $ position discharge occurrences of $ s $ color, and then the rest of casually put.
and $ g [k] = \ sum_ {i = k} ^ {lim} \ binom {i} {k} (- 1) ^ {ik} f [i] $
because we want to count the contribution, it requires $ g [1] .... g [ lim] $ , the above formula is $ O (lim ^ 2) $ in.
consider optimization:
the above $ \ binom {i} {k } $ expand to give $ g [k] = \ frac {1} {k!} \ sum_ {i = k} ^ {lim} \ frac! {(- 1) ^ {ik}} {! (ik)} f [i] \ times i $
make $ a [i] = \ frac {(- 1) ^ i} {i! } $, $ b [i] = f [i] \ times i! $, the $ g [k] = \ frac {1} {k!} \ sum_ {i = k} ^ {lim} a [ik] \ times b [i] $
this is a standard convolutional!
NTT can directly accelerate.

code:   

#include <bits/stdc++.h>  
#define N 800005
#define LL long long      
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;   
const LL G=3;   
const LL mod=1004535809;   
LL A[N],B[N],Ct[N],f[N],g[N],fac[10000008],inv[10000007],val[N];             
LL qpow(LL x,LL y) 
{
    LL tmp=1ll; 
    for(;y;y>>=1,x=x*x%mod) 
        if(y&1) 
            tmp=tmp*x%mod; 
    return tmp;    
}
LL Inv(LL x) { return qpow(x,mod-2); }        
void NTT(LL *a,int n,int flag) 
{
    int i,j,k,mid; 
    for(i=k=0;i<n;++i) 
    {
        if(i>k) swap(a[i],a[k]); 
        for(j=n>>1;(k^=j)<j;j>>=1);         
    }
    for(mid=1;mid<n;mid<<=1) 
    {
        LL wn=qpow(G,(mod-1)/(mid<<1));     
        if(flag==-1) wn=Inv(wn);   
        for(i=0;i<n;i+=(mid<<1))          
        {   
            LL w=1ll;    
            for(j=0;j<mid;++j) 
            {
                LL x=a[i+j],y=w*a[i+mid+j]%mod;         
                a[i+j]=(x+y)%mod,a[i+j+mid]=(x-y+mod)%mod;    
                w=w*wn%mod;   
            }
        }
    }
    if(flag==-1) 
    {
        LL re=Inv(n);          
        for(i=0;i<n;++i) a[i]=a[i]*re%mod;   
    }
}           
LL C(int x,int y) { return fac[x]*inv[y]%mod*inv[x-y]%mod; }      
int main() 
{
    // setIO("input");       
    int n,m,s,i,j,lim; 
    scanf("%d%d%d",&n,&m,&s);         
    for(i=0;i<=m;++i) scanf("%lld",&val[i]); 
    lim=min(m,n/s);   
    inv[0]=fac[0]=1ll;       
    int pp=max(n,m);     
    for(i=1;i<=pp;++i) 
    {
        fac[i]=fac[i-1]*1ll*i%mod;           
    }   
    inv[max(n,m)]=qpow(fac[max(n,m)],mod-2);
    for(i=max(n,m)-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;    
    for(i=0;i<=lim;++i) 
    {   
        f[i]=C(m,i)*fac[n]%mod*inv[n-i*s]%mod*qpow(inv[s],i)%mod*qpow(m-i,n-i*s)%mod*fac[i]%mod;       
    }       
    for(i=0;i<=lim;++i) A[i]=(inv[i]*(i&1?-1:1)+mod)%mod;    
    for(i=0;i<=lim;++i) B[lim-i]=f[i];         
    LL ans=0ll;               
    int tmp=1;     
    while(tmp<=lim*2) tmp<<=1;          
    NTT(A,tmp,1),NTT(B,tmp,1);   
    for(i=0;i<tmp;++i) Ct[i]=A[i]*B[i]%mod;  
    NTT(Ct,tmp,-1);                                    
    for(i=0;i<=lim;++i) g[i]=Ct[lim-i]*inv[i]%mod;            
    for(i=0;i<=lim;++i) 
    {                     
        (ans+=g[i]*val[i]%mod)%=mod;   
    } 
    printf("%lld\n",ans);    
    return 0;        
}

  

 

Guess you like

Origin www.cnblogs.com/guangheli/p/11884208.html