zoukankan      html  css  js  c++  java
  • bzoj5306: [Haoi2018]染色

    题目描述:

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

    思路:

    记 $F_i$ 表示出现了 $s$ 次的颜色有 $i$ 种。于是有
    $$
    Ans=sum_{i=1}^{n}w_i imes 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<bits/stdc++.h>
    #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;i<t;i++)if(i<v[i])swap(x[i],x[v[i]]);
        for(int wn,i=1;i<t;i<<=1){
            wn=ksm(G[op],(p-1)/(i<<1));
            for(int j=0;j<t;j+=(i<<1)){
                for(int k=0,w=1;k<i;k++,w=1ll*wn*w%p){
                    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;i<t;i++)x[i]=1ll*x[i]*k%p;
        }
    }
    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<t;i++)v[i]=(v[i>>1]>>1)|((i&1)<<l-1);
        ntt(a,0);ntt(b,0);
        for(int i=0;i<t;i++)a[i]=1ll*a[i]*b[i]%p;
        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
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    设置与获取Cookie
    事件对象详解
    兼容各浏览器的鼠标滚轮事件
    正则对象与正则表达式的基础学习
    Ajax 学习
    禅道使用流程概述
    Fiddler、Maven介绍
    Locust安装教程与使用
    常用工具软件包下载地址
    SVN合并步骤
  • 原文地址:https://www.cnblogs.com/Jessie-/p/10597927.html
Copyright © 2011-2022 走看看