bzoj5306: [Haoi2018]染色

题目描述:

有一块长度为 $n​$ 的画布,每个位置可以染成 $[1,m]​$ 这些颜色中的一种。 如果画布上恰好有 $k​$ 种颜色恰好出现了 $s​$ 次,则会产生 $w_k​$ 的愉悦度,求所有不同画布的愉悦度之和,对 $1004535809$ 取模。

思路:

 

记 $F_i$ 表示出现了 $s$ 次的颜色有 $i$ 种。于是有
$$
Ans=\sum_{i=1}^{n}w_i\times F_i
$$
考虑容斥计算表示 $F_i$ ,
$$
F_i=\sum_{j=i}^{n}(-1)^{j-i}C_{m}^{j}C_{n}^{j*s}\frac{(js)!}{(s!)^{j}}(m-j)^{n-js}C_{j}^{i}
$$
$C_{m}^{j}$ 表示从 $m$ 种颜色选中 $j$ 种颜色。

$C_{n}^{js}$ 表示从 $n$ 个位置中选出 $js$ 个。

$ \frac{(js)!}{(s!)^{j}}$ 表示 $js$ 个位置的排列方式。

$(m-j)^{n-j*s}$ 表示剩余的位置可以从 $(m-j)​$ 个颜色中任选。

$C_{j}^{i}$ 是充斥系数

式子化简后
$$
F_{i}=\frac{m!n!}{i!}\sum_{j=1}^{n}\frac{(m-j)^{n-js}}{(j-i)!(m-j)!(n-js)!(s!)^{j}}
$$
所以
$$
Ans=\sum_{i=0}^{n}m!n!\frac{w_i}{i!}\sum_{j=i}^{n}(-1)^{j-i}\frac{1}{(j-i)!(m-j)!}
$$
提前第二个 $\sum$
$$
Ans=m!n!\sum_{j=0}^{n}\frac{(m-j)^{n-js}}{(m-j)!(n-js)!(s!)^{j}}\sum_{i=0}^{j}\frac{wi}{i!}\frac{(-1)^{j-i}}{(j-i)!}
$$
发现后半部分式子可以卷积

效率 $O(nlogn)$

以下代码:

#include
#define il inline
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=4e5+5,M=1e7+2,p=1004535809;
int n,m,s,jc[M],a[N],b[N],G[2],t,l,v[N],ny[M],w[N];
il int read(){
   int x,f=1;char ch;
   _(!)ch=='-'?f=-1:f;x=ch^48;
   _()x=(x<<1)+(x<<3)+(ch^48);
   return f*x;
}
il int mu(int x,int y){
    return x+y>=p?x+y-p:x+y;
}
il int ksm(LL a,int y){
    LL b=1;
    while(y){
        if(y&1)b=b*a%p;
        a=a*a%p;y>>=1;
    }
    return b;
}
il void ntt(int *x,int op){
    for(int i=0;iif(i<v[i])swap(x[i],x[v[i]]);
    for(int wn,i=1;i1){
        wn=ksm(G[op],(p-1)/(i<<1));
        for(int j=0;j1)){
            for(int k=0,w=1;kp){
                int A=x[j+k],B=1ll*x[i+j+k]*w%p;
                x[j+k]=mu(A,B);x[i+j+k]=mu(A,p-B);
            }
        }
    }
    if(op){
        int k=ksm(t,p-2);
        for(int i=0;ip;
    }
}
int main()
{
    n=read();m=read();s=read();int R=min(m,n/s);
    G[0]=3;G[1]=ksm(G[0],p-2);int L=max(n,max(m,s));
    for(int i=0;i<=m;i++)w[i]=read();
    jc[0]=1;for(int i=1;i<=L;i++)jc[i]=1ll*i*jc[i-1]%p;
    ny[L]=ksm(jc[L],p-2);for(int i=L;i;i--)ny[i-1]=1ll*i*ny[i]%p;
    for(int i=0;i<=R;i++)a[i]=1ll*w[i]*ny[i]%p;
    for(int i=0;i<=R;i++)b[i]=(i&1)?p-ny[i]:ny[i];
    t=1;while(t<=(R<<1))t<<=1,l++;
    for(int i=0;i>1]>>1)|((i&1)<1);
    ntt(a,0);ntt(b,0);
    for(int i=0;ip;
    ntt(a,1);int ans=0;
    for(int i=0;i<=R;i++)
        ans=mu(ans,1ll*ksm(m-i,n-i*s)*a[i]%p*ny[m-i]%p*ny[n-i*s]%p*ksm(ny[s],i)%p);
    ans=1ll*ans*jc[n]%p*jc[m]%p;
    printf("%d\n",ans);
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Jessie-/p/10597927.html

你可能感兴趣的:(bzoj5306: [Haoi2018]染色)