Codeforces 1574F. Occurrences (2700)

题目描述

定义 \(a\) 的子序列是 \([a_l,a_{l+1},\cdots,a_r]\) 的连续子段构成的序列,定义序列 \(a\) 在序列 \(b\) 中出现的次数为序列 \(b\) 的子序列等于序列 \(a\) 的子序列数量。
\(n\) 个值域在 \([1,k]\) 的序列 \(A_1,A_2,\cdots,A_n\),要求构造一个长度为 \(m\)、值域在 \([1,k]\) 的序列 \(a\),满足对于所有序列 \(A_i\)\(A_i\) 在序列 \(a\) 中出现的次数大于等于任意一个 \(A_i\) 的子序列在序列 \(a\) 中出现的次数。
求满足这样条件的序列 \(a\) 的数量,答案对 \(998244353\) 取模。
\(1\le n,m,k,\sum |A_i|\le 3\cdot 10^5\)

考虑最严格的限制,即每个序列 \(A_i\) 在序列 \(a\) 中出现的次数得等于 \(A_i\) 中单个元素出现的次数。那么相当于出现一个元素 \(x\in A_i\),就要把 \(A_i\) 补全。

考虑怎样的条件会使得 \(A_i\) 不能被补全:

  • \(x\) 存在大于 \(1\) 个后继,此时不管填哪个都会导致另一个后继不被满足。同理,\(x\) 存在大于 \(1\) 个前驱也不满足,一个前驱后接 \(x\) 会导致另一个前驱接不到 \(x\)

  • 出现循环,例如有两个序列 \(\{1,2,3\},\{3,2,1\}\),此时无论怎么填都会使得出现的次数不够。

只需要记录每个元素的前驱后继个数,再用并查集判环。

最后再用所有合法的串进行背包 \(dp\),显然串的不同长度最多只有 \(O(\sqrt{k})\) 个,那么对同样长度的一起转移即可。

时间复杂度 \(O(n\alpha(n)+m\sqrt{k})\)。如果使用 \(\text{NTT}\) 复杂度可以降至 \(O(n\alpha(n)+m\log m)\)

\(\color{blue}{\text{code}}\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 5, mod = 998244353;
int n, m, k, y, lst, x, fa[N], l[N], r[N], fl[N], sz[N], p[N], f[N];
map <int, bool> mp[N]; vector <int> vec;
inline int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
int main() {
	scanf("%d%d%d", &n, &m, &k);
	for (int i = 1; i <= k; ++ i) fa[i] = i, sz[i] = 1;
	for (int i = 1; i <= n; ++ i) {
		scanf("%d%d", &y, &lst);
		while (-- y) {
			scanf("%d", &x);
			if (mp[lst][x]) { lst = x; continue; }
			mp[lst][x] = 1, ++ l[x], ++ r[lst];
			int fx = find(x), fy = find(lst);
			if (fx == fy) fl[x] = fl[lst] = 1;
			else sz[fx] += sz[fy], fa[fy] = fx; lst = x;
		}
	}
	for (int i = 1; i <= k; ++ i) if (l[i] > 1 || r[i] > 1 || fl[i]) fl[find(i)] = 1;
	for (int i = 1; i <= k; ++ i) if (find(i) == i && !fl[i]) ++ p[sz[i]];
	for (int i = 1; i <= k; ++ i) if (p[i]) vec.emplace_back(i);
	f[0] = 1;
	for (int i = 0; i <= m; ++ i)
		for (auto len : vec) if (i + len <= m)
			(f[i + len] += (ll)f[i] * p[len] % mod) %= mod;
	return printf("%d\n", f[m]), 0;
}
posted @ 2021-11-15 11:11  Samsara-soul  阅读(63)  评论(0编辑  收藏  举报