LOJ6519. 魔力环(莫比乌斯反演+生成函数)
题目链接
题解
这里给出的解法基于莫比乌斯反演。可以用群论计数的相关方法代替莫比乌斯反演,但两种方法的核心部分是一样的。
环计数的常见套路就是将环视为序列。我们统计所有不同的序列,那么对于最小循环节长度为 \(d\) 的序列对应的环就会被统计 \(d\) 次。因此假设最小循环节长度为 \(x\) 的合法序列数为 \(f(x)\),那么答案即为 \(\sum_\limits{d | {\rm gcd}(n, m)} \frac{1}{d}f(d)\)。
直接求 \(f(x)\) 不好求,使用莫比乌斯反演转化为求 \(g(x)\), \(g(x)\) 表示最小循环节长度为 \(x\) 的因子的合法序列个数。那么有 \(g(x) = \sum_\limits{d | x} f(d)\),即 \(f(x) = \sum_\limits{d | x} \mu(d) g(\frac{x}{d})\)。
我们假设整个长度为 \(n\) 的序列被分成了 \(l\) 段,每一段都是原序列的一个循环节。令 \(a = \frac{n}{l}, b = \frac{m}{l}\)(\(a\) 即为每一段的珠子数,\(b\) 即为每一段的黑色珠子数量),那么我们求 \(g(a)\),等价于求下面方程的整数解的数量:
\]
即被 \(a - b\) 颗白色珠子划分开的 \(a - b + 1\) 段黑色珠子的和为 \(b\),且满足每连续一段长度不超过 \(k\) 的限制条件。运用生成函数的知识,求上面方程的解的数量等同于求如下多项式 \(h(x)\) 中 \(x^b\) 的系数:
\]
进一步地,有:
\]
由于 \(\sum_\limits{i = 0}^k x^i = \frac{1 - x^{k + 1}}{1 - x}\),故:
\]
再展开右侧的式子 \(\sum_\limits{i = 0}^k(i + 1)x^i\):
\]
因此,我们得到了:
\]
其中,\((1 - x^{k + 1})^{a - b - 1}\) 可化为 \(\sum_\limits{i = 0}^{\infty}\binom{a - b - 1}{i}(-1)^ix^{(k + 1)i}\),而 \(\frac{1}{(1 - x)^{a - b + 1}}\) 即 \((1 - x)^{-(a - b + 1)}\),可通过负整数次幂的二项式定理化为 \(\sum_\limits{i = 0}^{\infty}\binom{a - b + i}{i}x^i\),那么可得:
\]
当把 \(h(x)\) 化成该形式后,要求 \(h(x)\) 中 \(x^b\) 的系数就变得非常简单了。记 \(s_1 = \sum_\limits{(k + 1)i + j = b}(-1)^i\binom{a - b - 1}{i}\binom{a - b+ j}{j}\),\(s_2 = (k + 2)\sum_\limits{(k + 1)i + j = b - k - 1}(-1)^i\binom{a - b - 1}{i}\binom{a - b+ j}{j}\),\(s_3 = (k + 1)\sum_\limits{(k + 1)i + j = b - k - 2}(-1)^i\binom{a - b - 1}{i}\binom{a - b+ j}{j}\),\(x^b\) 的系数为 \(w\),那么有 \(w = s_1 - s_2 + s_3\)。
求 \(s_1, s_2, s_3\) 只需按照 \(s_1, s_2, s_3\) 的式子枚举 \(i\) 即可,因为 \(i\) 确定 \(j\) 也就确定了。因此,我们可以在 \(\frac{b}{k + 1}\) 的时间内求出 \(h(x)\) 中 \(x^b\) 的系数。
除去反演部分,我们就能够在 \(\frac{\sigma(n)}{k + 1}\) 的时间内解决此题,其中,\(\sigma(n)\) 表示 \(n\) 的约数和。由于 \(\sigma(n)\) 可近似看作 \(n\ {\rm log}\ {\rm log}\ n\),接近线性,因此时间复杂度是非常优秀的。
代码
#include<bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long ll;
typedef long double ld;
typedef unsigned int uint;
typedef pair<int, int> pii;
typedef unsigned long long ull;
template<typename T> inline void read(T& x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template<typename T, typename... U> inline void read(T& x, U&... y) {
read(x), read(y...);
}
template<typename T> inline bool checkMax(T& a, const T& b) {
return a < b ? a = b, true : false;
}
template<typename T> inline bool checkMin(T& a, const T& b) {
return a > b ? a = b, true : false;
}
const int N = 1e5 + 10, mod = 998244353, G = 3;
int n, m, k;
inline void add(int& x, int y) {
if (y < 0) {
y += mod;
}
x = (x + y) % mod;
}
inline void mul(int& x, int y) {
x = 1ll * x * y % mod;
}
inline int qpow(int v, int p) {
int res = 1;
for (; p; p >>= 1, mul(v, v)) {
if (p & 1) {
mul(res, v);
}
}
return res;
}
inline int gcd(int x, int y) {
return !y ? x : gcd(y, x % y);
}
int p[N], pri[N], mu[N], fac[N], invfac[N], c;
inline int binom(int n, int m) {
return n < 0 || m < 0 || n < m ? 0 : 1ll * fac[n] * invfac[m] % mod * invfac[n - m] % mod;
}
void sieve(int n) {
mu[1] = 1;
for (register int i = 2; i <= n; ++i) {
p[i] = 1;
}
for (register int i = 2; i <= n; ++i) {
if (p[i]) {
mu[i] = -1, pri[++c] = i;
}
for (register int j = 1, d; j <= c && (d = pri[j] * i) <= n; ++j) {
p[d] = 0;
if (i % pri[j] == 0) {
mu[d] = 0; break;
} else {
mu[d] = -mu[i];
}
}
}
fac[0] = invfac[0] = 1;
for (register int i = 1; i <= n; ++i) {
mul(fac[i] = fac[i - 1], i);
}
invfac[n] = qpow(fac[n], mod - 2);
for (register int i = n - 1; i; --i) {
mul(invfac[i] = invfac[i + 1], i + 1);
}
}
inline int calc(int n, int m) {
int res = 0;
for (register int i = 0; i * (k + 1) <= m; ++i) {
int j = m - i * (k + 1);
add(res, 1ll * binom(n - m - 1, i) * binom(n - m + j, j) % mod * (i & 1 ? mod - 1 : 1) % mod);
j = m - i * (k + 1) - k - 1;
if (j >= 0) {
add(res, 1ll * (k + 2) * binom(n - m - 1, i) % mod * binom(n - m + j, j) % mod * (i & 1 ? 1 : mod - 1) % mod);
}
j = m - i * (k + 1) - k - 2;
if (j >= 0) {
add(res, 1ll * (k + 1) * binom(n - m - 1, i) % mod * binom(n - m + j, j) % mod * (i & 1 ? mod - 1 : 1) % mod);
}
}
return res;
}
int f[N], g[N];
int main() {
read(n, m, k);
sieve(n);
int d = gcd(n, m);
for (register int i = 1; i <= d; ++i) {
if (d % i) {
continue;
}
g[n / i] = calc(n / i, m / i);
}
for (register int i = 1; i <= n; ++i) {
for (register int j = i; j <= n; j += i) {
add(f[j], mu[i] * g[j / i]);
}
}
int ans = 0;
for (register int i = 1; i <= n; ++i) {
if (n % i == 0) {
add(ans, 1ll * f[i] * qpow(i, mod - 2) % mod);
}
}
printf("%d\n", ans);
return 0;
}
LOJ6519. 魔力环(莫比乌斯反演+生成函数)的更多相关文章
- Luogu4916 魔力环 莫比乌斯反演、组合、生成函数
传送门 先不考虑循环同构的限制,那么对于一个满足条件的序列,如果它的循环节长度为\(d\),那么与它同构的环在答案中就会贡献\(d\)次. 所以如果设\(f_i\)表示循环节长度恰好为\(i\)的满足 ...
- [jzoj 6084] [GDOI2019模拟2019.3.25] 礼物 [luogu 4916] 魔力环 解题报告(莫比乌斯反演+生成函数)
题目链接: https://jzoj.net/senior/#main/show/6084 https://www.luogu.org/problemnew/show/P4916 题目: 题解: 注: ...
- hdu1695 GCD(莫比乌斯反演)
题意:求(1,b)区间和(1,d)区间里面gcd(x, y) = k的数的对数(1<=x<=b , 1<= y <= d). 知识点: 莫比乌斯反演/*12*/ 线性筛求莫比乌 ...
- BZOJ 2154: Crash的数字表格 [莫比乌斯反演]
2154: Crash的数字表格 Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 2924 Solved: 1091[Submit][Status][ ...
- BZOJ2301: [HAOI2011]Problem b[莫比乌斯反演 容斥原理]【学习笔记】
2301: [HAOI2011]Problem b Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 4032 Solved: 1817[Submit] ...
- Bzoj2154 Crash的数字表格 乘法逆元+莫比乌斯反演(TLE)
题意:求sigma{lcm(i,j)},1<=i<=n,1<=j<=m 不妨令n<=m 首先把lcm(i,j)转成i*j/gcd(i,j) 正解不会...总之最后化出来的 ...
- 莫比乌斯函数筛法 & 莫比乌斯反演
模板: int p[MAXN],pcnt=0,mu[MAXN]; bool notp[MAXN]; void shai(int n){ mu[1]=1; for(int i=2;i<=n;++i ...
- 【BZOJ-2440】完全平方数 容斥原理 + 线性筛莫比乌斯反演函数 + 二分判定
2440: [中山市选2011]完全平方数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2371 Solved: 1143[Submit][Sta ...
- POI2007_zap 莫比乌斯反演
题意:http://hzwer.com/4205.html 同hdu1695 #include <iostream> #include <cstring> #include & ...
随机推荐
- ECShop研究:去掉标题中的Powered by ECShop和meta的<meta name="Generator" content="ECSHOP v2.7.3" />
本文以ECSHOP v2.7.3为说明,其他版本可能有所不同. 标题中的Powered by ECShop去除方法: 打开includes/lib_main.php文件: 找到156行:$page_t ...
- MAC通过SSH使用PEM文件登录
1.命令如下 ssh -i key.pem ssh -i key.pem root@IP 如果出现报错说明这个问题是文件的权限太大了,需要给小点 sudo chmod 600 key.pem 然后再执 ...
- ROS naviagtion analysis: costmap_2d--Costmap2DROS
博客转载自:https://blog.csdn.net/u013158492/article/details/50485418 在上一篇文章中moveBase就有关于costmap_2d的使用: pl ...
- Solidity string to uint
oraclize result以string格式返回,solidity没有uint(string)这样的强制转换功能,如果要解析其中的数字,可以用oraclize提供的parseInt方法: prag ...
- csv、txt读写及模式介绍
1读写模式 r以读方式打开文件,可读取文件信息 w已写方式打开文件,可向文件写入信息.如文件存在,则清空,再写入 a以追加模式打开文件,打开文件可指针移至末尾,文件不存在则创建 r+以读写方式打开文件 ...
- VS code docker 调试 asp.net core
前言 .net core的诞生就是为了解决跨平台的事情的,所以.net core app运行在linux.macOS.docker上也不是什么新鲜事了. 相信已经有不少.net core的项目已经部署 ...
- 编写高质量代码改善C#程序的157个建议——建议27:在查询中使用Lambda表达式
建议27:在查询中使用Lambda表达式 LINQ实际上是基于扩展方法和Lambda表达式的.任何LINQ查询都能通过扩展方法的方式来代替. var personWithCompanyList = f ...
- wpf使用truetype字体ttf
查了半天都是语焉不详,这篇算是稍微详细点的:http://www.cnblogs.com/junhengml/p/6878933.html 要先查找到字体的字库名称,才能使用: <Window. ...
- webapi put 请求405问题
put 请求的时候 浏览器会像服务器发送两个请求 如何没做任何配置第一个options请求是会报错的 这是需要配置路由给options作响应 这时options请求就通过了,然后你们会看到你的put ...
- 以太坊系列之十六:golang进行智能合约开发
以太坊系列之十六: 使用golang与智能合约进行交互 以太坊系列之十六: 使用golang与智能合约进行交互 此例子的目录结构 token contract 智能合约的golang wrapper ...