[CTS2019]珍珠
难度
思维难度 : 四星
代码难度 : 三星
标签
反演 + 计数 + 数学 + 生成函数 + \(fft\)
题解
设 \(cnt_x\) 表示第 \(x\) 种颜色的珍珠个数。求有多少种分配 \(cnt_x\) 的方案数,使 \(\sum_{i=1}^{D} \lfloor \frac{cnt_i}{2} \rfloor \geq m\)
发现这个式子很难求,所有推一下:
这样就只需要求至多有 \(n - 2m\) 种颜色的珍珠有奇数个的方案数, 求出恰好有 \(i\) \((i \leq n- 2m)\) 种颜色的珍珠有奇数个的方案数,然后加起来.
用二项式反演, 设 \(f_i\) 表示恰好有 \(i\) 种颜色的珍珠有奇数个的方案数,\(g_i\) 表示钦定有 \(i\) 种颜色的珍珠有奇数个的方案数.
发现这是一个减法卷积,得到 \(g_i\) 后就可以求出 \(f_i\) 了.
做减法卷积,如 \(h_k = \sum_{i=k}^{n}f_ig_{i-k}\) , 把 \(g_{i-k}\) 变成 \(g_{n - (i - k)}\) 就可以做加法卷积了. 相应的,原来的 \(h_k\) 在 \(h_{n+k}\)
然后就是求 \(g_i\)。
先考虑令钦定的 \(i\) 种颜色的珍珠有奇数个的方案数, 用 \(EGF\).
\([x^k]\frac{e^x - e^{-x}}{2}\) 的意义就是对于一种珍珠,一共有 \(k\) 个时的方案数.
那么 \([x^k](\frac{e^x - e^{-x}}{2})^p\) 的意义就是对于 \(p\) 种珍珠,一共有 \(k\) 个时的方案数.
剩下的个数任意,就是 \((e^x) ^ {D - p}\)。
于是有:
发现后面的东西是一个卷积,卷起来就好了
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#define int long long
using namespace std;
const int N = 1e6 + 10, mod = 998244353, G = 3;
int invG;
int tr[N];
int n, m, D;
int fac[N], ifac[N], inv[N];
int f[N], g[N];
int qpow(int a, int b) {
int res = 1;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
int add(int a, int b) {
return a + b >= mod ? a + b - mod : a + b;
}
int sub(int a, int b) {
return a - b < 0 ? a - b + mod : a - b;
}
void ntt(int *f, int n, int op) {
for (int i = 0; i < n; ++i) {
tr[i] = (tr[i >> 1] >> 1) | ((i & 1) ? (n >> 1) : 0);
}
for (int i = 0; i < n; ++i) {
if (i < tr[i]) swap(f[i], f[tr[i]]);
}
for (int p = 2; p <= n; p <<= 1) {
int len = p / 2;
int tG = qpow(op ? G : invG, (mod - 1) / p);
for (int l = 0; l < n; l += p) {
int buf = 1;
for (int k = l; k < l + len; ++k) {
int tmp = buf * f[k + len] % mod;
f[k + len] = sub(f[k], tmp);
f[k] = add(f[k], tmp);
buf = buf * tG % mod;
}
}
}
int invn = qpow(n, mod - 2);
if (op == 0) {
for (int i = 0; i < n; ++i) f[i] = f[i] * invn % mod;
}
}
void px(int *f, int *g, int n) {
for (int i = 0; i < n; ++i) f[i] = f[i] * g[i] % mod;
}
void mul(int *f, int *g, int n) {
int m = n;
for (n = 1; n <= m * 2; n <<= 1);
fill(f + m, f + n, 0);
fill(g + m, g + n, 0);
ntt(f, n, 1), ntt(g, n, 1);
px(f, g, n);
ntt(f, n, 0);
}
signed main() {
cin >> D >> n >> m;
if (n - 2 * m < 0) return 0;
if (n - 2 * m >= D) return cout << qpow(D, n), 0;
fac[1] = fac[0] = ifac[1] = ifac[0] = inv[1] = 1;
invG = qpow(G, mod - 2);
for (int i = 2; i <= D + 1; ++i) {
fac[i] = fac[i - 1] * i % mod;
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
ifac[i] = ifac[i - 1] * inv[i] % mod;
}
for (int i = 0; i <= D; ++i) {
if (i & 1) {
f[i] = sub(mod, qpow(sub(D, 2 * i), n) * ifac[i] % mod);
}
else {
f[i] = qpow(sub(D, 2 * i), n) * ifac[i] % mod;
}
g[i] = ifac[i];
}
mul(f, g, D + 1);
for (int i = 0; i <= D; ++i) {
f[i] = f[i] * fac[D] % mod * qpow(qpow(2, i), mod - 2) % mod * ifac[D - i] % mod * fac[i] % mod;
}
for (int i = 0; i <= D; ++i) {
if (i & 1) {
g[D - i] = sub(mod, ifac[i]);
}
else g[D - i] = ifac[i];
}
mul(f, g, D + 1);
int ans = 0;
for (int i = 0; i <= n - 2 * m; ++i) {
ans = add(ans, f[D + i] * ifac[i] % mod);
}
cout << ans << endl;
return 0;
}
总结
- 减法卷积可以通过翻转多项式来转化成加法卷积
- \(e^x\) 全是 \(1\) , \(e^{-x}\) 奇数位是 \(-1\) , 偶数位是 \(1\) 。 \(\frac{e^x - e^{-x}}{2}\) , 奇数位是 \(1\) , 偶数位是 \(0\) 。
原文地址:https://www.cnblogs.com/youwike/p/15132018.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python爬虫之scrapy的入门使用
- 告别传统工业互联网,提高数字管控思维:三维组态分布式能源站
- 爱奇艺iOS移动端网络优化实践:请求成功率优化
- Java数据类型
- Python爬虫之scrapy构造并发送请求
- Python爬虫之scrapy模拟登陆
- Python爬虫之scrapy中间件的使用
- Python爬虫之scrapy_redis原理分析并实现断点续爬以及分布式爬虫
- Python爬虫之scrapy_splash组件的使用
- Python爬虫之scrapy的日志信息与配置
- Python爬虫之scrapyd部署scrapy项目
- 最近发现一个很有趣的随机小姐姐视频源码 分享给大家
- Codeforces Round #633 (Div. 2)C Powered Addition (贪心,二进制)
- Spring 整合 JUnit
- Java Stax解析XML示例