[HAOI2018][bzoj5306] 染色 [容斥原理+NTT]

广告

蒟蒻のblog

思路

这道题的核心在于“恰好有\(k\)种颜色占了恰好\(s\)个格子”

这些“恰好”,引导我们去思考,怎么求出总的方案数呢?

分开考虑

考虑把恰好有\(s\)个格子的颜色,和不是\(s\)个颜色的格子分开来考虑

那么,显然答案可以用这样的一个式子表示:

令\(lim=min(\lfloor\frac ns\rfloor,m)\),那么:

\(ans=\sum_{i=0}^{lim}w_iC_m^iC_n^{is}\frac{(is)!}{(s!)^i}g(m-i,n-is)\)

其中\(g(i,j)\)表示把\(i\)种颜色放进\(j\)个格子里面,没有“恰好占了\(s\)个格子”的颜色的方案总数

这个\(g\)显然可以容斥原理来做

容斥原理

考虑对\(g\)用容斥原理推导,可得到如下公式:

\(g(i,j)=\sum_{k=0}^i(-1)^kC_i^kC_j^{ks}\frac{(ks)!}{(s!)^k}(i-k)^{j-ks}\)

把这个公式代回原式,可得到:

\(ans=\sum_{i=0}^{lim}w_iC_m^iC_n^{is}\frac{(is)!}{(s!)^i}\sum_{j=0}^{lim-i}(-1)^jC_{m-i}^jC_{n-is}^{js}\frac{(js)!}{(s!)^j}(m-i-j)^{n-is-js}\)

我们发现这个玩意儿好像比较复杂,没有什么特殊性质

难道这条路走不通?

构造卷积

我们发现后面的这个代表\(g\)的这一部分里面,有很多的\(j\)在,

那么我们想一想,\(j\)的枚举是所有比当前的\(i\)小的,那么只要把\(j\)用另一个东西:\(j-i\)替代了,然后把\(j\)变成所有比当前的大的,那么是不是和这个式子等价了呢?

说干就干!

\(ans=\sum_{i=0}^{lim}w_iC_m^iC_n^{is}\frac{(is)!}{(s!)^i}\sum_{j=lim-i}^{lim}(-1)^{j-i}C_{m-i}^{j-i}C_{n-is}^{js-is}\frac{(js-is)!}{(s!)^{j-i}}(m-j)^{n-js}\)

诶,这样一变化......后面的式子里这么多\(j-i\),前面又是\(i\),这让我们想到了什么?

处理卷积啊!

变换枚举方式

我们先把这些个烦人的组合数拆成阶乘的形式

\(ans=\sum_{i=0}^{lim}w_i\frac{m!n!}{i!(is)!(m-i)!(n-is)!}\frac{(is)!}{(s!)^i}\sum_{j=lim-i}^{lim}(-1)^{j-i}\frac{(m-i)!(n-is)!}{(j-i)!(js-is)!(m-j)!(n-js)!}\frac{(js-is)!}{(s!)^{j-i}}(m-j)^{n-js}\)

我们把左边的项挪进右边的最后一个sigma里面,然后把\(ij\)的枚举顺序反过来,得到:

\(ans=\sum_{j=0}^{lim}\sum_{i=0}^{j}w_i\frac{m!n!}{i!(is)!(m-i)!(n-is)!}\frac{(is)!}{(s!)^i}(-1)^{j-i}\frac{(m-i)!(n-is)!}{(j-i)!(js-is)!(m-j)!(n-js)!}\frac{(js-is)!}{(s!)^{j-i}}(m-j)^{n-js}\)

发现有很多项可以消掉了

\(ans=\sum_{j=0}^{lim}\sum_{i=0}^{j}w_i\frac{m!n!}{i!(s!)^i}(-1)^{j-i}\frac{1}{(j-i)!(m-j)!(n-js)!}\frac{1}{(s!)^{j-i}}(m-j)^{n-js}\)

再合并一下各个分数线

\(ans=\sum_{j=0}^{lim}\sum_{i=0}^{j}(-1)^{j-i}\frac{w_im!n!}{i!(s!)^j(j-i)!(m-j)!(n-js)!}(m-j)^{n-js}\)

把所有只含\(j\)的提到前面一个sigma去

\(ans=\sum_{j=0}^{lim}\frac{m!n!(m-j)^{n-js}}{(s!)^j(m-j)!(n-js)!}\sum_{i=0}^{j}\frac{(-1)^{j-i}w_i}{i!(j-i)!}\)

发现后面是一个卷积的形式!

设\(a(i)=\frac{w_i}{i!},b(i)=\frac{(-1)^i}{i!}\)

那么:

\(ans=\sum_{j=0}^{lim}\frac{m!n!(m-j)^{n-js}}{(s!)^j(m-j)!(n-js)!}(a\ast b)(j)\)

所有的逆元、阶乘都可以\(O(n)\)预处理,卷积使用模数为998244353的\(NTT\)来实现,总时间复杂度为\(O(n+limlog_2lim)\)

Code:

我的代码好像常数比较大......如果有知道怎么优化的dalao,麻烦在评论区帮忙指出一下!

不胜感激!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
inline ll read(){
    ll re=0,flag=1;char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') flag=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    return re*flag;
}
ll MOD=1004535809,g=3,f[10000010],finv[10000010],w[10000010],invlimit;
ll qpow(ll a,ll b){
    ll re=1;
    while(b){
        if(b&1) re=re*a%MOD;
        a=a*a%MOD;b>>=1;
    }
    return re;
}
ll A[400010],B[400010],r[400010],n,limit,cnt,m,S,N,invg;
void init(){
    limit=1;cnt=0;ll i;
    while(limit<=(N<<1)) limit<<=1,cnt++;
    for(i=0;i<limit;i++) r[i]=((r[i>>1]>>1)|((i&1)<<(cnt-1)));
    f[1]=finv[1]=f[0]=finv[0]=1;
    for(i=2;i<=max(max(n,m),S);i++){
        f[i]=f[i-1]*i%MOD;
    }
    finv[max(max(n,m),S)]=qpow(f[max(max(n,m),S)],MOD-2);
    for(i=max(max(n,m),S);i>=1;i--) finv[i-1]=finv[i]*i%MOD;
    invlimit=qpow(limit,MOD-2);invg=qpow(g,MOD-2);
}
void ntt(ll *a,ll type){
    ll i,j,k,mid,len;ll y,w,wn;
    for(i=0;i<limit;i++) if(i<r[i]) swap(a[i],a[r[i]]);
    for(mid=1;mid<limit;mid<<=1){
        len=mid<<1;
        wn=qpow(((type==1)?g:invg),(MOD-1)/len);
        for(j=0;j<limit;j+=len){
            w=1;
            for(k=0;k<mid;k++,w=w*wn%MOD){
                y=a[j+k+mid]*w%MOD;
                a[j+k+mid]=(a[j+k]-y+MOD)%MOD;
                a[j+k]=(a[j+k]+y)%MOD;
            }
        }
    }
    if(type==-1) for(i=0;i<limit;i++) a[i]=(a[i]*invlimit%MOD);
}
int main(){
    n=read();m=read();S=read();N=min(n/S,m);ll i;
    for(i=0;i<=m;i++) w[i]=read();
    init();
    for(i=0;i<=N;i++){
        A[i]=finv[i]*w[i]%MOD;
        B[i]=((i&1)?MOD-1:1)*finv[i]%MOD;
    }
    ntt(A,1);ntt(B,1);
    for(i=0;i<limit;i++) A[i]=A[i]*B[i]%MOD;
    ntt(A,-1);
    ll ans=0;
    for(i=0;i<=N;i++){
        ans=(ans+(finv[m-i]*finv[n-i*S]%MOD*qpow(finv[S],i)%MOD*qpow(m-i,n-i*S)%MOD*A[i]))%MOD;
    }
    printf("%lld\n",ans*f[n]%MOD*f[m]%MOD);
}

原文地址:https://www.cnblogs.com/dedicatus545/p/9159192.html

时间: 2024-08-30 18:29:32

[HAOI2018][bzoj5306] 染色 [容斥原理+NTT]的相关文章

【bzoj3456】城市规划 容斥原理+NTT+多项式求逆

题目描述 求出n个点的简单(无重边无自环)无向连通图数目mod 1004535809(479 * 2 ^ 21 + 1). 输入 仅一行一个整数n(<=130000) 输出 仅一行一个整数, 为方案数 mod 1004535809. 样例输入 3 样例输出 4 题解 容斥原理+NTT+多项式求逆 设 $f_i$ 表示 $i$ 个点的简单无向连通图的数目,$g_i$ 表示 $i$ 个点的简单无向图的数目. 根据定义得 $g_i=2^{\frac{n(n-1}2}$ . 对于 $f_i$ ,考虑容斥

【题解】方块染色(容斥原理+巧妙分类)

[题解]方块染色(容斥原理+巧妙分类) 刚开始以为是道容斥,写了这个错误程序 int main(){ pre(1e5); while(~scanf("%d%d",&n,&m)){ int ans=0; for(register int t=m,delta;t<=n;++t){ delta=0; for(register int k=1,d2;k<=n/t;++k){ d2=1ll*c(n/t,k)*(n-k*t+1)%mod*bin[n-k*t]%mod;

「HAOI2018」染色

题目链接:Click here Solution: 看到恰好,首先考虑容斥,设\(f[i]\)表示我们钦定\(i\)种颜色在序列中恰好出现了\(S\)次有多少种方案 那么现在就有\(i+1\)个部分,把他看作是可重集的全排列,方案数即 \({n! \over (S!)^i (n-Si)}\) ,后面每个都可以选 \((m-i)\) 种颜色 那么\(f[i]\)就是这样算的: \[ f[i]={m\choose i}\times {n! \over (S!)^i (n-Si)!} \times (

HAOI2018 简要题解

这套题是 dy, wearry 出的.学长好强啊,可惜都 \(wc\) 退役了.. 话说 wearry 真的是一个计数神仙..就没看到他计不出来的题...每次考他模拟赛总有一两道毒瘤计数TAT 上午的官方题解可以看 dy0607 的博客,写的挺详细的. 「HAOI2018」奇怪的背包 题意 小C非常擅长背包问题,他有一个奇怪的背包,这个背包有一个参数 \(P\) ,当他向这个背包内放入若干个物品后,背包的重量是物品总体积对 \(P\) 取模后的结果. 现在小C有 \(n\) 种体积不同的物品,第

HAOI2018 [HAOI2018]染色 【组合数 + 容斥 + NTT】

题目 为了报答小 C 的苹果, 小 G 打算送给热爱美术的小 C 一块画布, 这块画布可 以抽象为一个长度为 \(N\) 的序列, 每个位置都可以被染成 \(M\) 种颜色中的某一种. 然而小 C 只关心序列的 \(N\) 个位置中出现次数恰好为 \(S\) 的颜色种数, 如果恰 好出现了 \(S\) 次的颜色有 \(K\) 种, 则小 C 会产生 \(W_k\) 的愉悦度. 小 C 希望知道对于所有可能的染色方案, 他能获得的愉悦度的和对 1004535809 取模的结果是多少. 输入格式 从

luoguP4491 [HAOI2018]染色 广义容斥原理 + FFT

非常明显的摆了一个NTT模数.... 题目中求恰好\(k\),那么考虑求至少\(k\) 记\(g(k)\)表示至少\(k\)中颜色出现了恰好\(S\)次 那么,\[g(k) = \binom{M}{k} \frac{N!}{(S!)^k (N-Sk)!} * (M-k)^{N-Sk}\] 根据广义容斥原理,记\(f(i)\)表示恰好\(k\)种颜色出现了恰好\(k\)次 那么,\[f(i) = \sum \limits_{k = i}^M (-1)^{k - i} \binom{k}{i} g(

bzoj 5306 [HAOI2018] 染色

bzoj 5306 [HAOI2018] 染色 链接 推式子题 首先枚举有几种颜色选择恰好 \(s\) 次,可以得到一个式子: \[\sum _{i = 0} ^ {\min(\frac n s,m )} \frac {\binom n {i \cdot s} \binom m i (i \cdot s) ! \cdot f_i \cdot (m-i)^{n - is}} {(s!) ^ i} \] 但是,\(f_i\) 不能单纯地等于 \(w_i\), 因为会重复计算,我们不能保证当前选择的

P4491 [HAOI2018]染色

传送门 我觉得自己的数学也是够差的--一点思路也没有-- 考虑容斥,首先\(lim=min(m,n/S)\),设\(f[i]\)表示出现恰好\(S\)次的元素大于等于\(i\)种的情况,我们随便选\(i\)种颜色放\(S\)次,选的方法数有\(C_m^i\)种,然后染色可以看做是一个类似全排列的东西,每连续的几个染上同样的颜色,那么方案数为\(\frac{n!}{(S!)^i(n-S*i)!}\),前面颜色已经选定了,后面的每个有\(m-i\)种颜色可选,所以还要乘上一个\((m-i)^{n-S

【bzoj4487】[Jsoi2015]染色问题 容斥原理

题目描述 棋盘是一个n×m的矩形,分成n行m列共n*m个小方格.现在萌萌和南南有C种不同颜色的颜料,他们希望把棋盘用这些颜料染色,并满足以下规定: 1.  棋盘的每一个小方格既可以染色(染成C种颜色中的一种) ,也可以不染色. 2.  棋盘的每一行至少有一个小方格被染色. 3.  棋盘的每一列至少有一个小方格被染色. 4.  种颜色都在棋盘上出现至少一次. 以下是一些将3×3棋盘染成C = 3种颜色(红.黄.蓝)的例子: 请你求出满足要求的不同的染色方案总数.只要存在一个位置的颜色不同,即认为两