非常明显的摆了一个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. 解决Maven并行编译中出现打包错误问题的思路

    解决Maven并行编译中出现打包错误问题的思路 并行构建 Maven 3.x 提供了并行编译的能力,通过执行下列命令就可以利用构建服务器的多线程/多核性能提升构建速度: mvn -T 4 clean ...

  2. ES6简单总结

    1.变量声明let和const 我们都是知道在ES6以前,var关键字声明变量.无论声明在何处,都会被视为声明在函数的最顶部(不在函数内即在全局作用域的最顶部).这就是函数变量提升例如: functi ...

  3. 弹性盒模型justify-content属性

    justify-content是应用于父容器上来规定子元素在水平方向上的对齐方式的. flex-start 左对齐 flex-end 右对齐 center 居中 space-betten 两端对齐,两 ...

  4. 20165227 实验三《敏捷开发与XP实践》实验报告

    2017-2018-4 20165227 实验三<敏捷开发与XP实践>实验报告 实验内容 1.XP基础 2.XP核心实践 3.相关工具 实验要求 1.没有Linux基础的同学建议先学习&l ...

  5. Dream------scala--类的属性和对象私有字段实战详解

    Scala类的属性和对象私有字段实战详解 一.类的属性 scala类的属性跟java有比较大的不同,需要注意的是对象的私有(private)字段 1.私有字段:字段必须初始化(当然即使不是私有字段也要 ...

  6. Java Dom对XML的解析和修改操作

    与Dom4J和JDom对XML的操作类似,JDK提供的JavaDom解析器用起来一样方便,在解析XML方面Java DOM甚至更甚前两者一筹!其不足之处在于对XML的增删改比较繁琐,特开篇介绍... ...

  7. c# 通过Windows服务启动外部程序

    1. 新建一个Windows服务应用程序 创建项目——>Visual C# 左侧的"+"——>Windows ——>Windows 服务(右侧模板)——>输 ...

  8. spring 学习之二 AOP编程

    AOP概念 AOP, aspect oriented programing,翻译过来就是面向切面编程的意思,那什么叫面向切面编程呢?相对于之前传统的纵向继承方式来对原有功能进行功能扩展, 面向切面编程 ...

  9. 02 Go 1.2 Release Notes

    Go 1.2 Release Notes Introduction to Go 1.2 Changes to the language Use of nil Three-index slices Ch ...

  10. 1.SpringBoot之Helloword 快速搭建一个web项目

    背景: Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配 ...