非常明显的摆了一个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(k)$$

化成卷积式

\[f(i) * i! = \sum \limits_{k = i}^M \frac{(-1)^{k - i}}{(k - i)!} k! g(k)
\]

令\(F_i = \frac{(-1)^{i}}{i!}\),\(G_i = i! g(i)\)

记\(H_i\)表示\(f(i) * i\),那么

\[H_i = \sum \limits_{j = i}^M F(k - i) * G(k)
\]

反转下标,有

\[H_{n - i}' = \sum \limits_{i = 0}^{n - i} F(k) * G'(n - i - k)
\]

\(NTT\)即可,复杂度\(O(n \log n)\)


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; #define ri register int
#define rep(io, st, ed) for(ri io = st; io <= ed; io ++) #define gc getchar
inline int read() {
int p = 0, w = 1; char c = gc();
while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
return p * w;
} const int sid = 3e5 + 5;
const int cid = 1e7 + 5;
const int mod = 1004535809; inline int mul(int a, int b) { return 1ll * a * b % mod; }
inline int fp(int a, int k) {
int ret = 1;
for( ; k; k >>= 1, a = mul(a, a))
if(k & 1) ret = mul(ret, a);
return ret;
} int N, M, S, n, lg;
int fac[cid], inv[cid];
int rev[sid], f[sid], g[sid], w[sid], W[sid]; inline int C(int n, int m) {
if(n < m) return 0;
return mul(fac[n], mul(inv[m], inv[n - m]));
} inline void NTT(int *a) {
for(ri i = 0; i < n; i ++)
if(i < rev[i]) swap(a[i], a[rev[i]]);
for(ri i = 1; i < n; i <<= 1)
for(ri j = 0, kj = n / (i << 1); j < n; j += (i << 1))
for(ri k = j, kp = 0; k < i + j; k ++, kp += kj) {
int x = a[k], y = mul(w[kp], a[i + k]);
a[k] = (x + y >= mod) ? x + y - mod : x + y;
a[i + k] = (x - y < 0) ? x - y + mod : x - y;
}
} inline void calc() {
n = 1; lg = 0;
while(n <= M + M) n <<= 1, lg ++;
rep(i, 0, n) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
int g_ = fp(3, (mod - 1) / n);
w[0] = 1;
rep(i, 1, n) w[i] = mul(w[i - 1], g_); int lim = max(N, n);
fac[0] = fac[1] = inv[0] = inv[1] = 1;
rep(i, 2, lim) {
fac[i] = mul(fac[i - 1], i);
inv[i] = mul(inv[mod % i], mod - mod / i);
}
rep(i, 2, lim) inv[i] = mul(inv[i], inv[i - 1]); rep(i, 0, M - 1) f[i] = mul(inv[i], (i & 1) ? mod - 1: 1);
rep(i, 0, M) if(N >= S * i)
g[i] = 1ll*fac[i]*C(M,i)%mod*fac[N]%mod*fp(inv[S],i)%mod*inv[N-S*i]%mod*fp(M-i,N-S*i)%mod;
reverse(g, g + M + 1); NTT(f); NTT(g);
rep(i, 0, n) f[i] = mul(f[i], g[i]);
NTT(f);
int ivn = fp(n, mod - 2);
reverse(f + 1, f + n); reverse(f, f + M + 1);
rep(i, 0, n) f[i] = mul(f[i], mul(ivn, inv[i])); int ans = 0;
rep(i, 0, M) ans = (ans + mul(f[i], W[i])) % mod;
printf("%d\n", ans); } int main() {
N = read(); M = read(); S = read();
rep(i, 0, M) W[i] = read();
calc();
return 0;
}

luoguP4491 [HAOI2018]染色 广义容斥原理 + FFT的更多相关文章

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

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

  2. Luogu4491 [HAOI2018]染色 【容斥原理】【NTT】

    题目分析: 一开始以为是直接用指数型生成函数,后来发现复杂度不对,想了一下容斥的方法. 对于有$i$种颜色恰好出现$s$次的情况,利用容斥原理得到方案数为 $$\binom{m}{i}\frac{P_ ...

  3. [题解 LuoguP4491 [HAOI2018]染色

    传送门 神仙计数题 Orz 先令\(F[k]\)表示出现次数恰好为\(S\)次的颜色恰好有\(k\)中的方案数,那么 \[Ans=\sum\limits_{i=0}^mW_iF[i]\] 怎么求\(F ...

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

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

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

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

  6. [BZOJ5306] [HAOI2018]染色(容斥原理+NTT)

    [BZOJ5306] [HAOI2018]染色(容斥原理+NTT) 题面 一个长度为 n的序列, 每个位置都可以被染成 m种颜色中的某一种. 如果n个位置中恰好出现了 S次的颜色有 K种, 则小 C ...

  7. BZOJ 5306 [HAOI2018] 染色

    BZOJ 5306 [HAOI2018] 染色 首先,求出$N$个位置,出现次数恰好为$S$的颜色至少有$K$种. 方案数显然为$a_i=\frac{n!\times (m-i)^{m-i\times ...

  8. 【BZOJ5306】 [Haoi2018]染色

    BZOJ5306 [Haoi2018]染色 Solution xzz的博客 代码实现 #include<stdio.h> #include<stdlib.h> #include ...

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

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

随机推荐

  1. JavaScript 优雅的实现方式包含你可能不知道的知识点

    有些东西很好用,但是你未必知道:有些东西你可能用过,但是你未必知道原理. 实现一个目的有多种途径,俗话说,条条大路通罗马.很多内容来自平时的一些收集以及过往博客文章底下的精彩评论,收集整理拓展一波,发 ...

  2. python 面试题3

    注:本面试题来源于网络. 1.python下多线程的限制以及多进程中传递参数的方式 python多线程有个全局解释器锁(global interpreter lock),这个锁的意思是任一时间只能有一 ...

  3. 20165230 2017-2018-2 《Java程序设计》第9周学习总结

    20165230 2017-2018-2 <Java程序设计>第9周学习总结 教材学习内容总结 第十二章 java网络编程 学习了用于网络编程的类,了解URL.Socket.InetAdd ...

  4. Ubuntu下安装arm-linux-gnueabi-xxx编译器【转】

    转自:http://blog.csdn.net/real_myth/article/details/51481639 from: http://www.linuxdiyf.com/linux/1948 ...

  5. Java线程:新特征-有返回值的线程《转》

      原始文章   在Java5之前,线程是没有返回值的,常常为了“有”返回值,破费周折,而且代码很不好写.或者干脆绕过这道坎,走别的路了.   现在Java终于有可返回值的任务(也可以叫做线程)了. ...

  6. git —— 标签

    标签:为分支添加一个可读标识. 1.创建标签 操作步骤: 切换到需要打标签的分支上 $ git branch $ git checkout master 为当前分支新增一个标签 $ git tag v ...

  7. manacher模板

    转自:http://blog.csdn.net/zzkksunboy/article/details/72600679 作用 线性时间解决最长回文子串问题. 思想 Manacher充分利用了回文的性质 ...

  8. C压缩字符串中的空格

    使用纯C语言,去除一个字符串开头和结尾的空格,内部若有连续空格只保留一个.  C Code  12345678910111213141516171819202122232425262728293031 ...

  9. (三)HttpClient 抓取图片

    第一节: HttpClient 抓取图片 这里pom.xml需要用到io输入输出: <dependency> <groupId>commons-io</groupId&g ...

  10. 利用sys.dm_db_index_physical_stats查看索引大小/碎片等信息

    我们都知道,提高sql server的数据查询速度,最有效的方法,就是为表创建索引,而我们对数据表进行新增,删除,修改的时候,会产生索引碎片,索引碎片多了,对性能产生很大的影响,索引碎片越多对数据库查 ...