Min-Max容斥小记

\(Min-Max\) 容斥

又称 最值反演,主要是用于最大值和最小值一边好求一边难求的情况。
下面都已最小值求最大值为例,如果是最大值求最小值只需要把 \(\min,\max\) 交换。

基本形式

\(\max(S)\) 表示集合 \(S\) 中的最大值, \(\min(S)\) 表示集合 \(S\) 中的最小值,则有:

\[\max(S) = \sum\limits_{T \subset S, T \ne \emptyset}(-1)^{|T| - 1}\min(T) \]

证明:
\(S\) 中的元素 升序排序,如果两个元素相同认为编号大的元素更大。设排序后得到 \(a_1,\dots ,a_n\)

考虑一个 \(a_i\) 作为 \(\min(T)\) 出现的系数和:显然需要 \(a_i\) 被选上, \(a_1 \sim a_{i - 1}\) 都不能选, \(a_{i + 1} \sim a_n\) 任意选或不选,所以有:

\[f_i = \sum\limits_{j = 0}^{n - i}(-1)^{j}\binom{n - i}{j} = \sum\limits_{j = 0}^{n - i}(-1)^{j}(1)^{n - i - j}\binom{n - i}{j} = (1 - 1)^{n - i}=[i = n] \]

所以只有 \(a_n\) 的系数为 \(1\),其余 \(a_i\) 的系数都为 \(0\)

拓展形式

\(k-\max(S)\) 表示 集合 \(S\) 中的第 \(k\) 大值。那么有:

\[k-\max(S) = \sum\limits_{T\subset S, |T| \geq k}(-1)^{|T| - k} \binom{|T| - 1}{k - 1}\min(T) \]

不难发现令 \(k = 1\) 得到的就是基本形式。

证明:

\(S\) 中的元素 降序排序,如果两个元素大小相同认为编号大的元素大。设排序后得到序列 \(a_1,\dots ,a_n\)
设:

\[k-\max(S) = \sum\limits_{T \subset S}g(|T|)\min(T) \]

考虑 \(a_p\) 的贡献系数 \(f_p\)

\[f_p = \sum\limits_{i = 0}^{p - 1}g(i + 1)\binom{p - 1}{i} \]

因为 \(f_p = [p = k]\),所以有:

\[[p = k] = \sum\limits_{i = 0}^{p - 1}g(i + 1)\binom{p - 1}{i} \]

\(G(p) = [p + 1 = k]\)\(F(i) = g(i + 1)\)。 那么上式变为:

\[G(p) = \sum\limits_{i = 0}^{p}F(i)\binom{p}{i} \]

这是很标准的二项式反演式,根据二项式反演:(下列等式在 \(p < k - 1\) 时同样成立)

\[F(p) = \sum\limits_{i = 0}^{p}(-1)^{p - i}\binom{p}{i}G(i) = (-1)^{p - k + 1}\binom{p}{k - 1} \]

所以:

\[g(i) = F(i - 1) = (-1)^{i - k}\binom{i - 1}{k - 1} \]

\(Min-Max\) 容斥与期望

公式与理解

直接的 \(Min-Max\) 容斥好像并没什么用,因为一般情况下求 固定集合的极值 看起来两边难度都相同。但是一旦 Min-Max 容斥与期望结合就变得不同了,因为在期望的意义下\(\min\)\(\max\) 可能对应不同实际意义,那么求解难度也会发生改变。

首先我们需要明确一点:
对于两个随机变量 \(x_1, x_2\)\(E(\max(x_1, x_2)) \ne \max(E(x_1), E(x_2))\)。这个可以举个例子来理解:每次同时投掷两枚骰子,它们点数较大值的期望,显然不等于分别投掷两枚骰子求它们期望点数的较大值。因为第二种情况甚至期望点数都是相同的。

这也就意味着 对于求多个随机变量极值的期望,我们不能将这些变量变得独立。因此求 极值的期望 一般是比较困难的。

来理解 期望意义下 \(Min-Max\) 容斥核心公式

\[E(\max(S)) = \sum\limits_{\emptyset \ne T \subset S}(-1)^{|T| - 1}E(\min(T)) \]

它的含义是:对于一个由若干 随机变量 组成的集合 \(S\),这些 随机变量最大值的期望 等于所有 非空子集最小值的期望 乘容斥系数 再求和。

为什么是对的?
从期望的定义入手:期望就等于 所有情况的权值乘对应概率的和
那么我们考虑随机变量的一组取值 \(x_1',\dots,x_n'\),设它的出现概率为 \(p\)。那么这一组取值对期望的贡献为:

\[p \times \max(S) = p \times \sum\limits_{\empty \ne T \subset S}(-1)^{|T| - 1}\min(T) = \sum\limits_{\empty \ne T \subset S} (-1)^{|T| - 1} \times p \times \min(T) \]

注意到 \(\min(T)\) 是和 \(T\) 以外的变量无关的,因此可以对每个随机变量子集 \(T\) 算一遍贡献,它的贡献为:

\[\sum p_i \times (-1)^{|T| - 1} \times \min(T_i) = (-1)^{|T| - 1}\sum p_i \times \min(T_i) \]

其中 \(p_i\) 表示全集 \(S\) 的某组取值的概率,\(T_i\) 表示这组取值下 \(T\) 集合中所有变量的取值。
由于所有变量之间相互独立,因此 \(\sum p_i \times \min(T_i)\) 就等于 只考虑 \(T\) 中的变量,每组取值的最小值与对应概率的乘积求和,这显然就是 \(E(\min(T))\) 的定义。

所以 \(T\) 的贡献就是 \((-1)^{|T| - 1}E(\min(T))\)。那么有 \(E(\max(S)) = \sum\limits_{\emptyset \ne T \subset S}(-1)^{|T| - 1}E(\min(T))\) 成立。

类似的推导,可以得到:

\[E(k-\max(S)) = \sum\limits_{T \subset S, |T |\geq k}(-1)^{|T| - k}\binom{|T| - 1}{k - 1}E(\min(T)) \]

期望意义下的 \(Min-Max\) 容斥常用于解决一类 "期望多久可以覆盖所有元素" 的问题。
对于一个随机覆盖的过程,我们设 \(t_i\) 为一个随机变量 表示第 \(i\) 个元素被覆盖的时刻,那么要求的就是 \(E(\max(S))\)。根据公式,可以转化为求 \(E(\min(T))\),这等价于求 一个集合中的元素期望多长时间被第一次覆盖到

练习题

[HAOI2015] 按位或

题意:
给定 \(n\),有 \([0, 2^n - 1]\)\(2^n\) 个数字,数字 \(i\) 被抽到的概率是 \(p_i\)。初始你手上的数字 \(x = 0\),你需要每次从 \(2^n\) 个数字里随机抽取一个,不妨认为抽到的数字为 \(a\),然后令 \(x \gets (x | a)\)
\(x\) 第一次变成 \(2^n - 1\) 时停,问期望抽取次数。

\(n \leq 20\)

分析:
\(t_i\) 为一个随机变量表示第 \(i\) 位变成 \(1\) 的时刻,那么就是要求 \(E(\max(t_0,\dots,t_{n - 1}))\)
然后根据 \(Min-Max\) 容斥转化为求 \(E(\min(T))\),相当于求 \(T\) 中的数位第一次被覆盖到的期望次数。
发现这个是好算的,如果所有与 \(T\) 中的位有交的数字概率和是 \(P_T\),那么选出一个数字覆盖到 \(T\) 中的某个数位的概率就是 \(P_{T}\),期望 \(\frac{1}{P_{T}}\) 次选出一个这样的数字。
这样就好做了,做一遍高维前缀和可以求出所有 \(P_{T}\),进而能算出所有 \(f_T = (-1)^{|T - 1|}E(\min(T))\)。然后对 \(f_T\) 求一遍高维前缀和即可求出答案。
复杂度 \(O(n2^n)\)

CODE:

#include<bits/stdc++.h>
using namespace std;
const double eps = 1e-6;
int n, m;
double p[1 << 20], f[1 << 20];
inline int sz(int x) {return __builtin_popcount(x);}
inline double sign(int x) {return (x & 1) ? -1.0 : 1.0;}
inline void FMT(double *f, int n) {
	for(int i = 0; i < n; i ++ ) 
		for(int j = 0; j < (1 << n); j ++ ) 
			if(!(j >> i & 1)) f[j ^ (1 << i)] += f[j];
}
int main() {
	scanf("%d", &n); m = (1 << n);
	for(int i = 0; i < m; i ++ ) scanf("%lf", &p[i]);
	FMT(p, n);
	for(int i = 1; i < m; i ++ ) {
		if(fabs(1.0 - p[(m - 1) ^ i]) < eps) {puts("INF"); return 0;}
		f[i] = sign(sz(i) - 1) * 1.0 / (1.0 - p[(m - 1) ^ i]);
	}
	FMT(f, n);
	printf("%.10lf\n", f[m - 1]);
	return 0;
}

[ABC242Ex] Random Painting

题意:
\(n\) 个位置,最初都没有染色。有 \(m\) 个区间 \(l_i, r_i\),每次操作你需要从 \(m\) 个区间里等概率选出一个,然后将这个区间中的位置染色,所有位置均被染色后停止操作。问期望操作多少次。

\(1 \leq n, m \leq 400\)

分析:
裸的全覆盖求期望模型。但是这道题 \(n\) 比较大,我们不能暴力枚举子集。
注意到对于一个选定的集合位置 \(T\),我们关心的是有多少个区间至少包含了 \(T\) 中的一个位置,这可以转化成求有多少个区间与 \(T\) 交集为空。显然这样的区间一定在 \(T\) 排序后中某两个相邻的位置之间,我们只关注每个选定的位置的前驱是谁。

因此可以设计 \(dp\)
\(f_{i, j}\) 表示考虑了前 \(i\) 个位置,第 \(i\) 个位置被选在了 \(T\) 中,所有 \(r_i \leq i\) 的区间中有 \(j\) 个区间与选定的 \(T\) 交集为空的 \((-1)^{|T| - 1}\) 之和。
转移只需要枚举上一个选择的位置 \(k\),新增的无交区间数可以二维前缀和 \(O(1)\) 算出。

知道了 \(j\)\(f_{i, j}\),最后的答案也是容易算的。复杂度 \(O(n^2m)\)

CODE:

#include<bits/stdc++.h>
#define pb emplace_back
using namespace std;
const int N = 405;
typedef long long LL;
const LL mod = 998244353;
int n, m, l[N], r[N];
LL dp[N][N], sum[N], inv[N]; // dp[i][j] 表示最后选的位置是 i,有 j 个区间已经不交的方案数
vector< int > rn[N];
inline LL Pow(LL x, LL y) {
	LL res = 1, k = x;
	while(y) {
		if(y & 1) res = res * k % mod;
		y >>= 1;
		k = k * k % mod;
	}
	return res;
}
inline LL P(LL c) {return inv[c] * m % mod;}
int main() {
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; i ++ ) inv[i] = Pow(i, mod - 2);
	for(int i = 1; i <= m; i ++ ) {
		scanf("%d%d", &l[i], &r[i]);
		rn[r[i]].pb(i);
	}
	dp[0][0] = mod - 1;
	for(int i = 1; i <= n; i ++ ) {
		for(int j = 0; j <= m; j ++ ) {
			for(int k = i - 1; k >= 0; k -- ) {
				if(dp[k][j]) dp[i][j + sum[n] - sum[k]] = (dp[i][j + sum[n] - sum[k]] + dp[k][j] * (mod - 1) % mod) % mod;
			}
		}
		for(auto v : rn[i]) {
			for(int j = l[v]; j <= n; j ++ ) sum[j] ++;
		}
	}
	LL res = 0;
	for(int i = 1; i <= n; i ++ ) {
		for(int j = 0; j <= m; j ++ ) {
			if(dp[i][j]) res = (res + dp[i][j] * P(sum[i] - j) % mod) % mod;
		}
	}
	cout << res << endl;
	return 0;
}

[AGC038E] Gachapon

题意:
有一个随机数生成器, 生成 \([0, n - 1]\) 之间的整数,其中生成 \(i\) 的概率为 \(\frac{A_i}{S}\),其中 \(S = \sum\limits_{i = 0}^{n - 1}A_i\)
这个生成器不断随机生成数,当 \(\forall i \in [0, n - 1]\)\(i\) 至少出现了 \(B_i\) 次时,停止生成。否则继续生成。
问期望随机生成多少次,答案对 \(998244353\) 取模。

\(A_i, B_i \geq 1, \sum A_i,\sum B_i, n \leq 400\)

分析:
神仙题啊!!需要非常扎实的计数基本功才能做出来。

首先不难发现这还是一个全覆盖求期望的模型:设 \(t_i\) 为一个随机变量表示 \(i\) 的数量达到 \(B_i\) 的时刻,那么要求的就是 \(E(\max(S))\)。根据 \(Min-Max\) 容斥,转化为求 \(\sum(-1)^{|T| - 1}E(\min(T))\)

来考虑对于一个给定的 \(T\),怎么求 \((-1)^{|T| - 1} E(\min(T))\)
首先随机到一个 \(T\) 中的数字的概率为 \(\Large{\frac{\sum\limits_{x\in T} A_i}{\sum A_i}}\),那么期望随机 \(\Large{\frac{\sum A_i}{\sum\limits_{x\in T} A_i}}\) 次就有一次随机到的数字在 \(T\) 中。因此我们考虑计算 如果只存在 \(T\) 中的数字,\((-1)^{|T | - 1}E(\min(T))\) 是多少,然后乘上 \(\Large{\frac{\sum A_i}{\sum\limits_{x\in T} A_i}}\) 就是真实的答案。

如果只存在 \(T\) 中的数字,答案是多少呢?
\(E(\min(T))\) 的含义是最早某个数字达到 \(B_i\) 的期望次数。将随机的过程更形式的描述出来:

  • 定义数组 \(c_x\) 表示目前 \(T\) 中的元素 \(x\) 的出现次数,初始时 \(\forall x \in T, c_x = 0\)
  • 每次从 \(T\) 中随机一个元素 \(y\),令 \(c_y \gets c_y +1\)
  • 如果存在一个 \(p\) 满足 \(c_p \geq B_p\),那么结束随机。

\(\forall x \in T, c_x < B_x\) 的一个 \(\{c_i\}\) 为一个 不合法 状态。如果这个过程随机了 \(cnt\) 次,那么对期望的贡献就是 \(cnt \times p\)\(p\) 代表这个过程的概率。发现中间恰好经过了 \(cnt\) 个不合法的状态(从所有 \(c_i\) 都等于 \(0\) 算起),因此可以把贡献拆到每一步,相当于这个过程中每个不合法状态的概率加上 \(p\),最后求出所有不合法状态的概率和。

那么相当于我们要对于所有不合法状态,求出到达这个状态的概率。可以列出答案的式子:

\[\sum\limits_{T \subset S}(-1)^{|T| - 1}\frac{\sum A_i}{\sum\limits_{x\in T} A_i} \sum\limits_{\{c_x < B_x\}}\binom{\sum\limits_{x \in T} c_x}{c_{x_1},\dots,c_{x_k}}\prod\limits_{x\in T}(\frac{A_x}{\sum\limits_{x\in T}A_x})^{c_x} \]

其中 \(\Large{\binom{\sum\limits_{x \in T} c_x}{c_{x_1},\dots,c_{x_k}}}\) 表示可重集的全排列,可以拆成 \(\Large{\frac{(\sum\limits_{x\in T}c_x)!}{\prod\limits_{x \in T}c_x!}}\)
因此带入计算式就变成了:

\[\sum\limits_{T \subset S}(-1)^{|T| - 1}\frac{\sum A_i}{\sum\limits_{x\in T} A_i}\sum\limits_{\{c_x < B_x\}} \frac{(\sum\limits_{x\in T}c_x)!}{\prod\limits_{x \in T}c_x!} \prod\limits_{x\in T}(\frac{A_x}{\sum\limits_{x\in T}A_x})^{c_x} \]

考虑这个式子怎么计算:首先不难发现 \(\sum A_i\) 是定值,因此先不用管。我们从前往后考虑每个元素 \(x\) 是否选入 \(T\) 中,如果选入,那么枚举 \(c_x\) 表示钦定的状态,这个过程中可以计算出 \((-1)^{|T| - 1}\)\(A_x^{c_x}\)\(\frac{1}{c_x!}\),但是最后还需要乘上 \(\Large{\frac{\sum A_i}{\sum\limits_{x \in T}A_i}}\)\((\large{\sum\limits_{x \in T}c_x)!}\)\(\Large{(\frac{1}{\sum\limits_{x \in T}A_x}})^{\sum\limits_{x \in T}c_x}\)

因此设 \(dp_{i, j, k}\) 表示从前往后考虑到第 \(i\) 个元素,当前 \(T\) 中元素的 \(\sum\limits_{x \in T}A_x\)\(j\)\(\sum\limits_{x \in T}c_x\)\(k\)\(\large{(-1)^{|T| - 1}\prod\limits_{x \in T}\frac{A_x^{c_x}}{c_x!}}\) 的和。

转移是考虑 \(x\) 是否选入 \(T\) 中,如果不选入,那么继承上面的状态即可。如果选入,枚举 \(c_x\) 后可以 \(O(1)\) 转移。
最后算答案只需要将没乘的系数乘进去再加起来即可。

分析复杂度:
枚举 \(x\)\(c_x\) 的复杂度为 \(\sum B_i\),枚举 \(j, k\) 的复杂度为 \((\sum A_i)(\sum B_i)\),总复杂度就是 \(O((\sum A_i)(\sum B_i)^2)\)。类比背包的转移可以将空间复杂度优化至 \(O((\sum A_i)(\sum B_i))\)

CODE:

// 神仙题。 考察了 min-max 容斥, 和将期望拆到每一步的技巧
#include<bits/stdc++.h>
using namespace std;
const int N = 405;
typedef long long LL;
const LL mod = 998244353;
LL dp[N][N], fac[N], inv[N], Inv[N], pw[N][N]; // dp[i][j][k] 表示考虑了前 i 个, 钦定元素的所有 x 的 a_x 之和为 j,所有 c_x 为 k 的式子之和
int n, a[N], b[N]; 
inline LL Pow(LL x, LL y) {
	LL res = 1, k = x;
	while(y) {
		if(y & 1) res = res * k % mod;
		y >>= 1;
		k = k * k % mod;
	}
	return res;
}
int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++ ) scanf("%d%d", &a[i], &b[i]);
	fac[0] = 1; for(int i = 1; i < N; i ++ ) fac[i] = fac[i - 1] * i % mod;
	inv[N - 1] = Pow(fac[N - 1], mod - 2); for(int i = N - 2; i >= 0; i -- ) inv[i] = inv[i + 1] * (i + 1) % mod;
	for(int i = 1; i < N; i ++ ) Inv[i] = Pow(i, mod - 2);
	for(int i = 1; i <= n; i ++ ) {
		pw[i][0] = 1; for(int j = 1; j < b[i]; j ++ ) pw[i][j] = pw[i][j - 1] * a[i] % mod;
	}
	dp[0][0] = mod - 1;
	int sa = 0, sb = 0;
	for(int i = 0; i < n; i ++ ) {
		for(int j = sa; j >= 0; j -- ) 
			for(int k = sb - i; k >= 0; k -- ) 
				for(int l = 0; l < b[i + 1]; l ++ ) 
					dp[j + a[i + 1]][k + l] = (dp[j + a[i + 1]][k + l] + dp[j][k] * (mod - 1) % mod * inv[l] % mod * pw[i + 1][l] % mod) % mod;
		sa += a[i + 1]; sb += b[i + 1];
	}
	LL res = 0;
	for(int i = 1; i <= sa; i ++ ) 
		for(int j = 0; j <= sb; j ++ ) 
			res = (res + dp[i][j] * sa % mod * Inv[i] % mod * fac[j] % mod * Pow(Pow(i, mod - 2), j) % mod) % mod;
	cout << res << endl;
	return 0;
}

P4707 重返现世

题意:

\(n\) 种物品,每次你可以从中随机抽取一种,第 \(i\) 种物品被抽到的概率为 \(\frac{p_i}{m}\)。当抽取到的物品种类数达到 \(k\) 种停止,求期望抽取次数。

\(1 \leq n \leq 10^3, 1\leq k \leq n, 0 \leq n - k \leq 10, 0\leq p_i \leq m, \sum p_i = m, 1 \leq m \leq 10^4\)

分析:
如果 \(k = n\) 那么就是正常的全覆盖求期望模型。

\(k \ne n\) 实际上差不多。设 \(t_i\) 为一个随机变量表示第 \(i\) 种物品被抽到时的抽取次数,令 \(t = n - k + 1\),那么要求的就是 \(E(t-\max(S))\)

这类覆盖问题 \(\max\) 的期望显然不如 \(\min\) 的期望好求,因此考虑公式:

\[E(t-\max(S)) = \sum\limits_{T \subset S, |T| \geq t}(-1)^{|T| - t}\binom{|T| - 1}{t - 1}E(\min(T)) \]

对于给定集合 \(T\),有 \(\large{E(\min(T)) = \frac{m}{\sum\limits_{x \in T}p_x}}\)

因此有一个直接的暴力 \(dp\) 是设 \(f_{i, j, k}\) 表示考虑了前 \(i\) 中物品,当前钦定了 \(j\) 种在 \(T\) 中,钦定的物品的 \(\sum p_x\) 之和为 \(k\)\((-1)^{|T| - t}\) 之和。求出这个后最后乘上组合数和期望加起来就是答案。

但是这样复杂度是 \(O(n^2m)\) 的,显然无法通过。

注意到 \(n - k \leq 10\),考虑从这里入手:

这意味这 \(t\) 比较小。我们来思考 \(\binom{|T| - 1}{t - 1}\) 有什么实际意义,等价于对于所有钦定 \(T\) 中的物品,除去第一个物品,剩下的任意选 \(t - 1\) 个的方案数

那么能不能把这个系数在 \(dp\) 的过程中算进去呢?发现是可以的,只需要我们在钦定 \(T\) 的过程中同时钦定是否也在 \(t\) 中,就可以把一种方案算 \(\binom{|T| - 1}{t - 1}\) 次。

那么这时侯就不用记录有多少种在 \(T\) 里了。我们设 \(f_{i, 0/1, j, k}\) 表示考虑了前 \(i\) 种物品,当前是否已经钦定了物品在 \(T\) 中,当前已经钦定了 \(j\)\(T\) 中的物品在 \(t\) 里,当前所有 \(T\) 里物品的 \(\sum p_x\) 之和为 \(k\)\((-1)^{|T| - t}\) 的和。其中第二维的存在意义是 第一个钦定在 \(T\) 中的物品一定不能在 \(t\) 里,需要这个状态来判断当前能否往 \(t\) 里钦定

状态数 \(O(ntm)\),转移可以 \(O(1)\),最后求答案就是枚举 \(k\),用 \(f_{n, 0/1, t - 1, k}\) 乘上期望加起来。第一维可以滚掉,空间复杂度 \(O(tm)\),时间复杂度 \(O(tnm)\)

CODE:

// 裸的 k-Max 容斥
#include<bits/stdc++.h>
using namespace std;
const int M = 1e4 + 10;
const int N = 1e3 + 10;
typedef long long LL;
const LL mod = 998244353;
int n, k, m, t, p[N];
LL inv[M], dp[11][2][M]; // dp[i][j][o][k] 表示考虑了前 i 个原料,已经钦定了 j 个 在 t 里, 是否已经有在 |T| 中的元素, 当前 p 之和为 k 的 (-1)^{|T| - t} 的和
inline LL Pow(LL x, LL y) {
	LL res = 1LL, k = x;
	while(y) {
		if(y & 1) res = res * k % mod;
		y >>= 1;
		k = k * k % mod;
	}
	return res;
}
int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n >> k >> m; t = n - k + 1; // 要求的 E(t-max)
	for(int i = 1; i <= m; i ++ ) inv[i] = Pow(i, mod - 2);
	for(int i = 1; i <= n; i ++ ) cin >> p[i];
	dp[0][0][0] = (t & 1) ? mod - 1 : 1; int sp = 0;
	for(int i = 0; i < n; i ++ ) {
		for(int j = min(i, t - 1); j >= 0; j -- ) 
			for(int o = 1; o >= 0; o -- ) 		
				for(int k = sp; k >= 0; k -- ) 
					if(dp[j][o][k]) {
						// 钦定 i + 1 在 T 里:
						// 不钦定在 t 里面
						dp[j][o | 1][k + p[i + 1]] = (dp[j][o | 1][k + p[i + 1]] + dp[j][o][k] * (mod - 1) % mod) % mod;
						// 钦定在 t 里面
						if(o && j + 1 <= t - 1) dp[j + 1][o | 1][k + p[i + 1]] = (dp[j + 1][o | 1][k + p[i + 1]] + dp[j][o][k] * (mod - 1) % mod) % mod; 
					}
		sp += p[i + 1];
	}
	LL res = 0;
	for(int k = 0; k <= sp; k ++ ) {
		res = (res + (dp[t - 1][0][k] + dp[t - 1][1][k]) % mod * inv[k] % mod * m % mod) % mod;
	}
	cout << res << endl;
	return 0;
}

\(Gcd-Lcm\) 反演

\(Min-Max\) 容斥在 \(gcd-lcm\) 上同样适用,可以根据 \(Min-Max\) 容斥推出 \(Gcd-Lcm\) 反演式。

公式

\[lcm(S) = \sum\limits_{T \subset, T \ne \emptyset}gcd(T)^{(-1)^{|T| - 1}} \]

证明:

\(S\) 中的数仅包含 \(p_1,\dots,p_k\) 这些质因子。
那么一个数 \(a_x \in S\) 可以表示成 \(\large{a_x = \prod\limits_{i = 1}^{k}p_i^{t_{x, i}}}\) 的形式。

注意到,

\[lcm(S) = \prod\limits_{i = 1}^{k}p_i^{\max(t_{1, i}, \dots t_{n, i})} \]

实际上就是每个质因数的幂次取 \(\max\) 然后乘起来。那么对指数使用 \(Min-Max\) 容斥:

\[lcm(S) = \prod\limits_{i = 1}^{k}p_i^{\sum\limits_{T \subset S}(-1)^{|T| - 1}\min(T)_i} \]

其中 \(\min(T)_i\) 表示 \(T\) 中的数在 \(p_i\) 上的最小幂次。
可以将指数上的 \(\sum\) 变成累乘的形式:

\[lcm(S) = \prod\limits_{i = 1}^{k}\prod\limits_{T \subset S, T \ne \emptyset}p_i^{(-1)^{^{|T|- 1}}\min(T)_i} \]

可以交换前后两个 \(\prod\) 符号:

\[lcm(S) = \prod\limits_{T \subset S, T \ne \emptyset}\prod\limits_{i = 1}^{k}p_i^{(-1)^{|T| - 1}\min(T)_i}=\prod\limits_{T \subset S, T \ne \empty}(\prod\limits_{i = 1}^{k}p_i^{\min(T)_i})^{(-1)^{|T| - 1}} = \prod\limits_{T \subset S, T \ne \emptyset}gcd(T)^{(-1)^{|T| - 1}} \]

证毕。

练习题

CF1687E Become Big For Me

咕咕咕。

BZOJ4833 最小公倍佩尔数

咕咕咕

posted @ 2026-09-09 20:36  Czl2007  阅读(4)  评论(0)    收藏  举报