BZOJ 5306 [HAOI2018] 染色

BZOJ 5306 [HAOI2018] 染色

首先,求出$N$个位置,出现次数恰好为$S$的颜色至少有$K$种。

方案数显然为$a_i=\frac{n!\times (m-i)^{m-i\times s}}{(m-K)!\times (s!)^K}\times C(m,K)$

然后二项式反演一下,得到恰好的数量:$ans_i=\sum\limits_{j=i}^n (-1)^{j-i}\times a_i\times C(j,i)$

然后展开一下就可以得到两个多项式:$A_i=\frac{m!\times n!\times (m-i)^{m-i\times s}}{(m-i)!\times (n-s\times i)!\times (s!)i},b_i=\frac{(-1){m-i}}{(m-i)!}$

然后显然答案方案数就是:$C=A\times B ,ans_i=\frac{C[m+i]}{i!}$

最后加一下权即可!

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <iostream>
#include <bitset>
using namespace std;
#define N 262205
#define ll long long
#define mod 1004535809
int a[N],b[N],w[N],n,m,s,lim,fac[10000005],inv[10000005],ans;
int q_pow(int x,int n){int ret=1;for(;n;n>>=1,x=(ll)x*x%mod)if(n&1)ret=(ll)ret*x%mod;return ret;}
#define inv(x) q_pow(x,mod-2)
void NTT(int *a,int len,int flag)
{
    int i,j,k,t,w,x,tmp;
    for(i=k=0;i<len;i++)
    {
        if(i>k)swap(a[i],a[k]);
        for(j=len>>1;(k^=j)<j;j>>=1);
    }
    for(k=2;k<=len;k<<=1)
    {
        t=k>>1;x=q_pow(3,(mod-1)/k);if(flag==-1)x=inv(x);
        for(i=0;i<len;i+=k)
            for(j=i,w=1;j<i+t;j++)
            {
                tmp=(ll)w*a[j+t]%mod;
                a[j+t]=(a[j]-tmp+mod)%mod;
                a[j]=(a[j]+tmp)%mod;w=(ll)w*x%mod;
            }
    }if(flag==-1)for(i=0,t=inv(len);i<len;i++)a[i]=(ll)a[i]*t%mod;
}
void init()
{
    int lim=max(n,m);fac[0]=1;
    for(int i=1;i<=lim;i++)fac[i]=(ll)i*fac[i-1]%mod;inv[lim]=q_pow(fac[lim],mod-2);
    for(int i=lim;i;i--)inv[i-1]=(ll)i*inv[i]%mod;
    lim=min(m,n/s);
    for(int i=0;i<=lim;i++)a[i]=(ll)fac[m]*inv[m-i]%mod*fac[n]%mod*inv[n-s*i]%mod*q_pow(inv[s],i)%mod*q_pow(m-i,n-i*s)%mod;
    for(int i=0;i<=m;i++)
        if((m-i)&1)b[i]=mod-inv[m-i];
        else b[i]=inv[m-i];
}
int main()
{
    scanf("%d%d%d",&n,&m,&s);init();
    for(int i=0;i<=m;i++)scanf("%d",&w[i]);
    int len=1;while(len<=(m<<1))len<<=1;
    NTT(a,len,1);NTT(b,len,1);for(int i=0;i<len;i++)a[i]=(ll)a[i]*b[i]%mod;NTT(a,len,-1);
    for(int i=0;i<=m;i++)ans=(ans+(ll)w[i]*a[m+i]%mod*inv[i])%mod;
    printf("%d\n",ans);
}
posted @ 2019-03-29 19:14  Winniechen  阅读(133)  评论(0编辑  收藏  举报