$ \color{#0066ff}{ 题目描述 }$

为了报答小 C 的苹果, 小 G 打算送给热爱美术的小 C 一块画布, 这块画布可 以抽象为一个长度为 \(N\) 的序列, 每个位置都可以被染成 \(M\) 种颜色中的某一种.

然而小 C 只关心序列的 \(N\) 个位置中出现次数恰好为 \(S\) 的颜色种数, 如果恰 好出现了 \(S\) 次的颜色有 \(K\) 种, 则小 C 会产生 \(W_k\) 的愉悦度.

小 C 希望知道对于所有可能的染色方案, 他能获得的愉悦度的和对 \(1004535809\) 取模的结果是多少.

\(\color{#0066ff}{输入格式}\)

从标准输入读入数据. 第一行三个整数 \(N, M, S\).

接下来一行 \(M + 1\) 个整数, 第 \(i\) 个数表示 \(W_{i-1}\) .

\(\color{#0066ff}{输出格式}\)

输出到标准输出中. 输出一个整数表示答案.

\(\color{#0066ff}{输入样例}\)

8 8 3
3999 8477 9694 8454 3308 8961 3018 2255 4910 55 96 4
396135414 150956526 115846323 684016411 478047433 741809293 841489850 30757425 354718 455244385 67265783 601148661 653297520 159551113 659259694 422602824 890944094 515558436 708977878 859628263 674258521 366153708 146971849 6161187 658301233 461136214 471709361 18786219 349277110 525215286 508995440 640141358 994347874 337617068 743448773 691546444 504640221 401810440 113565512 194628996 99765846 419008498 110931344 659189735 171012254 255189228 896007913 104632201 451664101 178069999 952991431 840513981 647057140 692809264 931718019 30010246 380306874 368517911 154597143 770763865 497641686 772741050 919136255 321190494 134863734 372165464 743950576 11194552 760810101 386902866 928594467 936096033 784108853 271133783 330481696 61402412 432546315 837809841 492881572 200968716 472860533 777800538 858285842 716767711 483244349 497540302 436003214 827152949 390815935 567741247 468900425 37709000 257282045 362991016 500424354 943931245 116395951

\(\color{#0066ff}{输出样例}\)

524070430

231524284

\(\color{#0066ff}{数据范围与提示}\)

特殊性质: \(\forall 1 \le i \le m, W_i = 0\)

对于 \(100\%\) 的数据, 满足 \(0 \le W_i < 1004535809\)

\(\color{#0066ff}{题解}\)

我们发现,如果钦定k种颜色出现S次,然后剩下位置的颜色选择肯定是m-k这些颜色,但是可能还会有颜色出现S次,我们并不能很容易的计算,于是考虑容斥

我们记一个\(f[i]\)表示出现S次的颜色\(\ge i\)种的方案数,这样设状态就可以不用管刚刚的问题了

然后我们考虑f的计算

首先,钦定i种颜色,组合数\(C_m^i\),每种出现了S次,于是剩下的位置的个数就是\(n-iS\)

剩下的位置我们肯定是颜色随便选,注意不能选钦定的!所以方案显然是\((m-i)^{n-iS}\)

注意还有一部分贡献,就是颜色的位置!于是我们直接可重集排列一下,就是\(\frac{n!}{(S!)^i*(n-iS)!}\)

于是,我们f的计算方式就出来了\(f[i] = C_m^i*(m-i)^{n-iS}*\frac{n!}{(S!)^i*(n-iS)!}\)

然后我们计算答案,设\(ans[i]\)为出现S次颜色恰好i种的方案数,就是用f容斥一下

\(\begin{aligned}ans[i]=\sum_{j=i}^m(-1)^{j-i}*C_j^i*f[j]\end{aligned}\)

实际上并不用到m,可以发现,有贡献的最多同时存在的颜色种类数是\(min\{m, \frac n S\}\)

然后拆开组合数\(\begin{aligned}ans[i]=\sum_{j=i}^m(-1)^{j-i}*\frac{j!}{i!*(j-i)!}*f[j]\end{aligned}\)

然后稍微动一下,大致类似的放在一起\(\begin{aligned}ans[i]=\frac{1}{i!}\sum_{j=i}^m\frac{(-1)^{j-i}}{(j-i)!}*j!*f[j]\end{aligned}\)

显然这是个卷积的形式,直接翻转一下

\(\begin{aligned}ans[i]=\frac{1}{i!}\sum_{j=i}^m\frac{(-1)^{m-j+i+1}}{(m-j+i+1)!}*j!*f[j]\end{aligned}\)

然后NTT就行了。。

#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int mod = 1004535809;
const int maxn = 1e7 + 100;
LL ksm(LL x, LL y) {
LL re = 1LL;
while(y) {
if(y & 1) re = re * x % mod;
x = x * x % mod;
y >>= 1;
}
return re;
}
int len, r[maxn];
using std::vector;
void FNTT(vector<int> &A, int flag) {
A.resize(len);
for(int i = 0; i < len; i++) if(i < r[i]) std::swap(A[i], A[r[i]]);
for(int l = 1; l < len; l <<= 1) {
int w0 = ksm(3, (mod - 1) / (l << 1));
for(int i = 0; i < len; i += (l << 1)) {
int w = 1, a0 = i, a1 = i + l;
for(int k = 0; k < l; k++, a0++, a1++, w = 1LL * w * w0 % mod) {
int tmp = 1LL * A[a1] * w % mod;
A[a1] = ((A[a0] - tmp) % mod + mod) % mod;
A[a0] = (A[a0] + tmp) % mod;
}
}
}
if(!(~flag)) {
int inv = ksm(len, mod - 2);
std::reverse(A.begin() + 1, A.end());
for(int i = 0; i < len; i++) A[i] = 1LL * A[i] * inv % mod;
}
}
vector<int> operator * (vector<int> A, vector<int> B) {
int tot = A.size() + B.size() - 1;
for(len = 1; len <= tot; len <<= 1);
for(int i = 0; i < len; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) * (len >> 1));
FNTT(A, 1), FNTT(B, 1);
vector<int> C;
for(int i = 0; i < len; i++) C.push_back(1LL * A[i] * B[i] % mod);
FNTT(C, -1);
C.resize(tot);
return C;
}
int n, m, fac[maxn], inv[maxn], S, w[maxn];
int C(int x, int y) { return 1LL * fac[x] * inv[y] % mod * inv[x - y] % mod; }
void predoit() {
fac[0] = 1;
for(int i = 1; i < maxn; i++) fac[i] = 1LL * fac[i - 1] * i % mod;
inv[maxn - 1] = ksm(fac[maxn - 1], mod - 2);
for(int i = maxn - 2; i >= 0; i--) inv[i] = 1LL * inv[i + 1] * (i + 1) % mod;
}
int main() {
n = in(), m = in(), S = in();
predoit();
for(int i = 0; i <= m; i++) w[i] = in();
int limit = std::min(m, n / S);
vector<int> A, B;
for(int i = 0; i <= limit; i++) {
A.push_back(1LL * C(m, i) * ksm(m - i, n - i * S) % mod * fac[n] % mod * ksm(inv[S], i) % mod * inv[n - i * S] % mod * fac[i] % mod);
B.push_back((limit - i) & 1? mod - inv[limit - i] : inv[limit - i]);
}
A = A * B;
int now = 0;
for(int i = 0; i <= limit; i++) (now += 1LL * w[i] * A[i + limit] % mod * inv[i] % mod) %= mod;
printf("%d\n", now);
return 0;
}

P4491 [HAOI2018]染色 容斥+NTT的更多相关文章

  1. LOJ2527 HAOI2018 染色 容斥、生成函数、多项式求逆

    传送门 调了1h竟然是因为1004535809写成了998244353 "恰好有\(K\)种颜色出现了\(S\)次"的限制似乎并不容易达到,考虑容斥计算. 令\(c_j\)表示强制 ...

  2. [BZOJ5306][HAOI2018]染色(容斥+FFT)

    https://www.cnblogs.com/zhoushuyu/p/9138251.html 注意如果一开始F(i)中内层式子中j枚举的是除前i种颜色之外还有几种出现S次的颜色,那么后面式子就会难 ...

  3. P4491 [HAOI2018]染色 广义容斥 NTT 生成函数

    LINK:染色 算是比较常规的广义容斥. 算恰好k个 可以直接转成至少k个. 至少k个非常的好求 直接生成函数. 设\(g_k\)表示至少有k个颜色是满足的 那么有 \(g_k=C(m,k)\frac ...

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

    题目 为了报答小 C 的苹果, 小 G 打算送给热爱美术的小 C 一块画布, 这块画布可 以抽象为一个长度为 \(N\) 的序列, 每个位置都可以被染成 \(M\) 种颜色中的某一种. 然而小 C 只 ...

  5. [HAOI2018]染色(容斥+NTT)

    补充一篇详细得不能再详细的题解,比如让我自己看懂. 可能与前面的题解有些相同,我想补充一下自己的想法. 显然,最多 \(K\) 最大为 \(N=min(\lfloor \frac nS\rfloor, ...

  6. HAOI 2018 染色(容斥+NTT)

    题意 https://loj.ac/problem/2527 思路 设 \(f(k)\) 为强制选择 \(k\) 个颜色出现 \(s\) 种,其余任取的方案数. 则有 \[ f(k)={m\choos ...

  7. [洛谷P4491] [HAOI2018]染色

    洛谷题目链接:[HAOI2018]染色 题目背景 HAOI2018 Round2 第二题 题目描述 为了报答小 C 的苹果, 小 G 打算送给热爱美术的小 C 一块画布, 这块画布可 以抽象为一个长度 ...

  8. luogu P4491 [HAOI2018]染色

    传送门 这一类题都要考虑推式子 首先推出题目要求的式子,枚举正好有\(s\)个颜色的种类(范围\([0,p=min(\lfloor\frac{n}{s}\rfloor,m)]\)),然后对于后面的颜色 ...

  9. BZOJ5306 HAOI2018染色(容斥原理+NTT)

    容易想到枚举恰好出现S次的颜色有几种.如果固定至少有i种恰好出现S次,那么方案数是C(M,i)·C(N,i*S)·(M-i)N-i*S·(i*S)!/(S!)i,设为f(i). 于是考虑容斥,可得恰好 ...

随机推荐

  1. UGUI防止穿透和判断点击的是否是UI

    用UGUI做的UI,比如按钮,点击一下,后面的3D物体也会接收到点击事件! 1.UGUI自带的防穿透代码: if (EventSystem.current.IsPointerOverGameObjec ...

  2. Codeforces 76D 位运算

    题意:给你两个数x 和 y, x = a + b, y = a XOR b,问有没有合法的a和b满足这个等式? 思路:有恒等式: a + b = ((a & b) << 1) + ...

  3. CloudStack 注册模板脚本分析

    注册系统虚拟机模板 /usr/share/cloudstack-common/scripts/storage/secondary/cloud-install-sys-tmplt 内容如下: usage ...

  4. git 常用commands(转)

    常用 Git 命令清单   作者: 阮一峰 日期: 2015年12月 9日 我每天使用 Git ,但是很多命令记不住. 一般来说,日常使用只要记住下图6个命令,就可以了.但是熟练使用,恐怕要记住60- ...

  5. python学习之内部执行流程,内部执行流程,编码(一)

    python的执行流程: 加载内存--->词法分析--->语法分析--->编译--->转换字节码---->转换成机器码---->供给CPU调度 python的编码: ...

  6. 如何快速增加pdf书签,解除pdf限制

    一.需要的工具 福昕PDF阅读器 Foxit PDF Editor 2.2.1 build 1119 汉化版 下载地址:http://www.onlinedown.net/soft/51002.htm ...

  7. Linux上获取CPU Core个数的实现

    Linux上获取CPU Core个数的实现 可以通过多种手段取得CPU Core的个数,如: 1) 调用系统提供的函数get_nprocs(),可以在头文件sys/sysinfo.h中发现它 2) 借 ...

  8. 团体程序设计天梯赛L2-002 链表去重 2017-03-22 18:12 25人阅读 评论(0) 收藏

    L2-002. 链表去重 时间限制 300 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 给定一个带整数键值的单链表L,本题要求你编写程序,删除 ...

  9. 深入理解java虚拟机(五)垃圾收集器

    垃圾收集器 垃圾收集器是垃圾收集算法的具体实现.Java规范对垃圾收集器的实现没有做任何规定,因此不同的虚拟机提供的垃圾收集器可能有很大差异.HotSpot虚拟机1.7版本使用了多种收集器.如下图. ...

  10. 【小梅哥SOPC学习笔记】设置Eclipse在编译(build)前自动保存源代码文件

    设置Eclipse在编译(build)前自动保存源代码文件 Eclipse 常用设置之让Eclipse在编译(build)前自动保存源代码文件 一.让Eclipse在编译(build)前自动保存源代码 ...