1. 程式人生 > >P4491 [HAOI2018] 染色

P4491 [HAOI2018] 染色

.org ever -- 多項式 rac max all lose print

題目鏈接

題意分析

要求\(k\)種顏色恰好出現\(S\)

也就是出現\(S\)次的顏色恰好有\(k\)

我們可以發現\(lim=max\{k\}=min(\frac{n}{s},{m})\)

我們可以容斥一下 就是

出現\(S\)次的顏色至少存在\(k\)

那麽

\[dp[k]=C_m^kC_{n}^{ks}(m-k)^{m-ks}\]

應該和好理解的

出現\(S\)次的顏色恰好\(k\)種就是

\[ans[k]=\sum_{j=k}^{lim}(-1)^{j-k}C_j^kdp[j]\]

\(j\)種顏色中\(k\)種被重復算了\(C_j^k\)

那麽我們拆開就是

\[ans[k]* k!=\sum_{j=k}^{lim}\frac{(-1)^{j-k}}{(j-k)!}dp[j]* j!\]

如何求\(\sum_{j=k}^{lim}\frac{(-1)^{j-k}}{(j-k)!}dp[j]* j!\)

我們考慮維護出

\[a[i]=dp[i]* i!\ \ \ \ \ \ b[i]=\frac{(-1)^{i}}{i!}\]

然後就是套路 翻轉\(a\)序列

那麽就是多項式乘法\(NTT\)

那麽對應就是\(lim-j+j-k=lim-k\)

所以我們再反轉一下就可以了

然後累加就可以了

CODE:

/*-------------OI使我快樂-------------*/
int n,m,s,have,lim,all;
ll ans;
ll fav[M],fac[M],inv[M],num[M];
ll dp[M],cdy[M],wzy[M];
int key[M];
IL ll C(int x,int y)
{return fac[x]*fav[x-y]%mod*fav[y]%mod;}
IL ll qpow(ll x,ll y)
{ll res=1;for(;y;y>>=1,x=x*x%mod) if(y&1) res=res*x%mod;return res;}
IL void NTT(ll *A,int knd)
{
    for(R int i=0;i<lim;++i) if(i<key[i]) swap(A[i],A[key[i]]);
    for(R int mid=1;mid<lim;mid<<=1)
    {
        ll Wn=qpow(knd==1 ? 3:Gi,(mod-1)/(mid<<1));
        for(R int j=0;j<lim;j+=(mid<<1))
        {
            ll w=1;
            for(R int k=0;k<mid;++k,w=w*Wn%mod)
            {
                ll x=A[j+k],y=w*A[j+k+mid]%mod;
                A[j+k]=(x+y)%mod;A[j+k+mid]=(x-y+mod)%mod;
            }
        }
    }
    if(knd==-1)
    {
        ll inv=qpow(lim,mod-2);
        for(R int i=0;i<lim;++i) A[i]=A[i]*inv%mod;
    }
}
int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    read(n);read(m);read(s);have=min(n/s,m);
    for(R int i=0;i<=m;++i) read(num[i]),num[i]%=mod;
    fac[0]=fac[1]=fav[0]=fav[1]=inv[0]=inv[1]=1;
    for(R int i=2;i<=10000000;++i)
    {
        fac[i]=fac[i-1]*i%mod;
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;
        fav[i]=fav[i-1]*inv[i]%mod;
    }
//  for(R ll i=1;i<=10;++i) printf("%lld%c",fac[i],(i==10 ? '\n':' '));
    for(R int i=0;i<=have;++i)
    dp[i]=C(m,i)*C(n,i*s)%mod*fac[i*s]%mod*qpow(fav[s],i)%mod*qpow(m-i,n-i*s)%mod;
//  for(R ll i=0;i<=have;++i)
//  printf("%lld%c",dp[i],(i==have ? '\n':' '));
    for(R int i=0;i<=have;++i)
    {
        cdy[i]=(((i&1) ? -1:1)*fav[i]%mod+mod)%mod;
        wzy[i]=dp[i]*fac[i]%mod;
    } 
    reverse(wzy,wzy+have+1);
    for(lim=1;lim<=(have<<1);lim<<=1) ++all;
    for(R int i=0;i<lim;++i) key[i]=((key[i>>1]>>1)|((i&1)<<(all-1)));
    NTT(cdy,1);NTT(wzy,1);
    for(R int i=0;i<lim;++i) cdy[i]=cdy[i]*wzy[i]%mod;
    NTT(cdy,-1);
    reverse(cdy,cdy+have+1);
    for(R int i=0;i<=have;++i) ans=(ans+num[i]*cdy[i]%mod*fav[i]%mod)%mod;
    printf("%lld\n",(ans%mod+mod)%mod);
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

HEOI 2019 RP++

P4491 [HAOI2018] 染色