只要你跑的够快,锅就追不上你

0%

「ARC 096E」Everything On It(容斥原理)

题目大意

「ARC 096E」Everything On It

求有多少个子集族,满足:

  • 其中的每个子集都是 $[n]$ 的一个子集;
  • 任意两个子集互不相同;
  • $1, 2, \cdots, n$ 都在其中出现了至少两次。

答案对素数 $m$ 取模。

数据范围:$n \le 3000, 10^8 \le m \le 10^9 + 9$。

思路分析

我们考虑容斥,枚举出现了不超过一次的数的个数 $i$,这样答案就是 $\sum_{i = 0}^{n} (-1)^i \binom{n}{i} A_i$。

对于某个 $i$,我们不妨假定出现次数不超过一次的数是 $1, 2, \cdots, i$。考虑继续枚举包含 $[1, i]$ 中数的子集个数 $j$。对于除了这 $j$ 个集合以外的集合,它们都不包含前 $i$ 个数,所以方案数是 $2^{2^{n - i}}$。而对于这 $j$ 个集合,发现它们必定两两不同。它们的后 $n - i$ 位共有 $(2^{n - i})^j$ 种可能的取值,而前 $i$ 位每一位都出现了不超过 $1$ 次。这相当于从前 $i$ 个数中选出 $k$ 个数钦定它们没有出现,然后把剩下 $i - k$ 个数分给 $j$ 个集合(第二类斯特林数)。这样,我们已经可以得到答案的式子:

直接计算的时间复杂度是 $O(n^3)$,不能通过。我们考虑把枚举 $k$ 变为直接计算某个式子。发现下面的等式始终成立:

考虑该等式的组合意义:左边是将 $n$ 个不同的小球选一些出来,然后划成 $k$ 个集合;右边是将 $n + 1$ 个小球划成 $k + 1$ 个集合。我们把第 $n + 1$ 个小球看作特殊小球,它被划分到的集合中的所有球都会被扔掉,这样两边的组合意义就相同了,我们就证明了这个等式。

于是原式可以简化为:

枚举 $i, j$ 直接计算即可,时间复杂度 $O(n^2)$。

代码实现

1
#include <bits/stdc++.h>
2
using namespace std;
3
4
const int maxn = 3e3;
5
int n, mod, C[maxn + 3][maxn + 3], S[maxn + 3][maxn + 3];
6
7
inline int func(int x) {
8
	return x < mod ? x : x - mod;
9
}
10
11
int qpow(int a, int b, int m = mod) {
12
	int c = 1;
13
	for (; b; b >>= 1, a = 1ll * a * a % m) {
14
		if (b & 1) c = 1ll * a * c % m;
15
	}
16
	return c;
17
}
18
19
void prework(int n) {
20
	C[0][0] = S[0][0] = 1;
21
	for (int i = 1; i <= n; i++) {
22
		C[i][0] = 1;
23
		for (int j = 1; j <= i; j++) {
24
			C[i][j] = func(C[i - 1][j - 1] + C[i - 1][j]);
25
			S[i][j] = (1ll * S[i - 1][j] * j + S[i - 1][j - 1]) % mod;
26
		}
27
	}
28
}
29
30
int main() {
31
	scanf("%d %d", &n, &mod);
32
	prework(n + 1);
33
	int ans = 0;
34
	for (int i = 0; i <= n; i++) {
35
		int x = i & 1 ? mod - C[n][i] : C[n][i], s = 0;
36
		x = 1ll * x * qpow(2, qpow(2, n - i, mod - 1)) % mod;
37
		for (int j = 0; j <= i; j++) {
38
			int y = qpow(2, (n - i) * j);
39
			y = 1ll * y * S[i + 1][j + 1] % mod;
40
			s = func(s + y);
41
		}
42
		ans = (ans + 1ll * x * s) % mod;
43
	}
44
	printf("%d\n", ans);
45
	return 0;
46
}