题目链接

https://loj.ac/problem/6519

题解

这里给出的解法基于莫比乌斯反演。可以用群论计数的相关方法代替莫比乌斯反演,但两种方法的核心部分是一样的。

环计数的常见套路就是将环视为序列。我们统计所有不同的序列,那么对于最小循环节长度为 \(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)\),等价于求下面方程的整数解的数量:

\[x_0 + x_1 + ... + x_{a - b} = b(0 \leq x_i \leq k, 0 \leq x_0 + x_{a - b} \leq k)
\]

即被 \(a - b\) 颗白色珠子划分开的 \(a - b + 1\) 段黑色珠子的和为 \(b\),且满足每连续一段长度不超过 \(k\) 的限制条件。运用生成函数的知识,求上面方程的解的数量等同于求如下多项式 \(h(x)\) 中 \(x^b\) 的系数:

\[h(x) = \left(\sum_{i = 0}^{k} x^i\right) ^ {a - b - 1} \left( \left(\sum_{i = 0}^{k} x^i\right)^2{\rm mod}\ x^{k + 1}\right)
\]

进一步地,有:

\[h(x) = \left(\sum_{i = 0}^{k} x^i\right) ^ {a - b - 1} \left(\sum_{i = 0}^{k} (i +1)x^i\right)
\]

由于 \(\sum_\limits{i = 0}^k x^i = \frac{1 - x^{k + 1}}{1 - x}\),故:

\[h(x) = \left(\frac{1 - x^{k + 1}}{1 - x}\right) ^ {a - b - 1} \left(\sum_{i = 0}^{k} (i +1)x^i\right)
\]

再展开右侧的式子 \(\sum_\limits{i = 0}^k(i + 1)x^i\):

\[\begin{aligned}\sum_{i = 0}^k (i +1)x^i &= x^0 + 2x^1 + 3x^2 + \cdots + (k + 1)x^k\\ &= (x^0 + x^1 + \cdots + x^k) + (x^1 +x^2 + \cdots + x^k)+ \cdots + x^k \\ &= \frac{x^0 - x^{k + 1}}{1 - x} + \frac{x^1 - x^{k + 1}}{1 - x} + \cdots + \frac{x^k - x^{k - 1}}{1 - x} \\ &= \frac{\frac{x^0 - x^{k + 1}}{1 - x} - (k + 1)x^{k + 1}}{1 - x} \\ &= \frac{1 - (k + 2)x^{k + 1} + (k + 1)x^{k + 2}}{(1 - x)^2}\end{aligned}
\]

因此,我们得到了:

\[\begin{aligned}h(x) &= \left(\frac{1 - x^{k + 1}}{1 - x}\right) ^ {a - b - 1} \frac{1 - (k + 2)x^{k + 1} + (k + 1)x^{k + 2}}{(1 - x)^2} \\ &= \frac{(1 - x^{k + 1})^{a - b - 1}}{(1 - x)^{a - b + 1}}(1 - (k + 2)x^{k + 1} + (k + 1)x^{k + 2})\end{aligned}
\]

其中,\((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) = \left(\sum_{i = 0}^{\infty}\binom{a - b - 1}{i}(-1)^ix^{(k + 1)i}\right)\left(\sum_{i = 0}^{\infty}\binom{a - b + i}{i}x^i\right)(1 - (k + 2)x^{k + 1} + (k + 1)x^{k + 2})
\]

当把 \(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. 魔力环(莫比乌斯反演+生成函数)的更多相关文章

  1. Luogu4916 魔力环 莫比乌斯反演、组合、生成函数

    传送门 先不考虑循环同构的限制,那么对于一个满足条件的序列,如果它的循环节长度为\(d\),那么与它同构的环在答案中就会贡献\(d\)次. 所以如果设\(f_i\)表示循环节长度恰好为\(i\)的满足 ...

  2. [jzoj 6084] [GDOI2019模拟2019.3.25] 礼物 [luogu 4916] 魔力环 解题报告(莫比乌斯反演+生成函数)

    题目链接: https://jzoj.net/senior/#main/show/6084 https://www.luogu.org/problemnew/show/P4916 题目: 题解: 注: ...

  3. hdu1695 GCD(莫比乌斯反演)

    题意:求(1,b)区间和(1,d)区间里面gcd(x, y) = k的数的对数(1<=x<=b , 1<= y <= d). 知识点: 莫比乌斯反演/*12*/ 线性筛求莫比乌 ...

  4. BZOJ 2154: Crash的数字表格 [莫比乌斯反演]

    2154: Crash的数字表格 Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 2924  Solved: 1091[Submit][Status][ ...

  5. BZOJ2301: [HAOI2011]Problem b[莫比乌斯反演 容斥原理]【学习笔记】

    2301: [HAOI2011]Problem b Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 4032  Solved: 1817[Submit] ...

  6. Bzoj2154 Crash的数字表格 乘法逆元+莫比乌斯反演(TLE)

    题意:求sigma{lcm(i,j)},1<=i<=n,1<=j<=m 不妨令n<=m 首先把lcm(i,j)转成i*j/gcd(i,j) 正解不会...总之最后化出来的 ...

  7. 莫比乌斯函数筛法 & 莫比乌斯反演

    模板: int p[MAXN],pcnt=0,mu[MAXN]; bool notp[MAXN]; void shai(int n){ mu[1]=1; for(int i=2;i<=n;++i ...

  8. 【BZOJ-2440】完全平方数 容斥原理 + 线性筛莫比乌斯反演函数 + 二分判定

    2440: [中山市选2011]完全平方数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2371  Solved: 1143[Submit][Sta ...

  9. POI2007_zap 莫比乌斯反演

    题意:http://hzwer.com/4205.html 同hdu1695 #include <iostream> #include <cstring> #include & ...

随机推荐

  1. 【总结整理】关于房产app的比较

    从切换城市的分类方式就能看出来,因覆盖城市很多,搜房网(房天下)跟安居客都用上了拼音选房,而链家因城市很少,只需简单罗列即可. 搜房网(房天下)覆盖城市多达651个,覆盖范围最广,安居客为500个,两 ...

  2. Luogu 4784 [BalticOI 2016 Day2]城市

    斯坦纳树复习,我暑假的时候好像写过[JLOI2015]管道连接来着. 设$f_{i, s}$表示以$i$为根,$k$个重要点的连通状态为$s$,($0$代表没有连进最小生成树里面去,$1$代表连进了最 ...

  3. readfile()

    readfile()将一个文件写入到输出缓存参数1:文件名

  4. linux蓝屏时间修改

    setterm -blank 2   #/etc/profile里添加这样一句话,可以让屏幕2分钟后没有信号(蓝屏) setterm -blank 0   #/etc/profile里添加这样一句话, ...

  5. Struts2 让跳转指定执行某个方法

    很多时候,我们想让jsp页面中的某个超链接,点击后执行后台的某个方法,里面该如何做呢? 这里方法很多种 我举例两种: 1.在struts.xml配置,配置如下: <package name=&q ...

  6. MYSQL常用日期操作

    mysql查询今天.昨天.7天.近30天.本月.上一月 数据 今天 select * from 表名 where to_days(时间字段名) = to_days(now()); 昨天 SELECT ...

  7. LoadRunner监控Linux条件和解决方法

    注:内容来自网络 需要下载3个包: (1)rsh-0.17-14.i386.rpm (2)rsh-server-0.17-14.i386.rpm (3)rpc.rstatd-4.0.1.tar.gz ...

  8. python-输入

    1. python2版本中 咱们在银行ATM机器前取钱时,肯定需要输入密码,对不? 那么怎样才能让程序知道咱们刚刚输入的是什么呢?? 大家应该知道了,如果要完成ATM机取钱这件事情,需要先从键盘中输入 ...

  9. 第五篇 Python内置函数

    内置函数 abs() delattr() hash() memoryview() set() all()    dict()  help() min() setattr() any()  dir()  ...

  10. 「BZOJ 3123」「SDOI 2013」森林「启发式合并」

    题意 你有一个森林,你需要支持两个操作 查询两个结点路径上权值第\(k\)小 两个点之间连一条边 强制在线,结点数\(\leq 8\times 10^4\) 题解 如果可以离线,这就是一个主席树板子题 ...