Codeforces 1620G. Subsequences Galore (2400)
定义函数 \(f([t_1,t_2,\cdots,t_m])\) 为不同的是至少一个 \(t_i\) 的子序列的字符串数量。其中,\(f([])=0\)。
给定 \(n\) 个字符串 \(s_1,s_2,\cdots,s_n\),每个字符串的字符都是有序的\((\)即,先是若干a
,再是若干b
,\(\cdots\),最后是若干z
\()\)。
求所有 \(2^n\) 个 \(n\) 个字符串的子集的 \(f\) 函数值,答案对 \(998244353\) 取模。
\(1\le n\le 23,1\le |s_i|\le 2\cdot 10^4\)。
挺简单的 \(\color{red}{\text{Div2 }}\color{purple}{\text{G}}\)。
首先考虑容斥。比如 \(f([s_1,s_2])=f([s_1])+f([s_2])-\)是 \(s_1\) 且是 \(s_2\) 的子序列的字符串数量。
同理,\(f([S])\) 关于 \(f([T])(T\subset S)\) 的表达式也可容易得到。
如果直接枚举子集转移是 \(O(3^n)\) 的,高维前缀和优化后时间复杂度为 \(O(n2^n)\)。
那么问题就转化成了求若干字符串的公共子序列个数,由于此题每个字符串的字符都是有序的,那么考虑合法串的任意一个字母的数量不能超过集合中任意一个字符串中这个字母的数量,也就是 \(\text{the number of the letter ? in }S'\le \min\{\text{the number of the letter ? in } s_i\}(s_i\in S)\),其中 \(S'\) 是公共子序列。
根据乘法原理,公共子序列数也就是\((\)所有集合中的字符串字母 \(a\) 的数量的最小值\(+1)\) \(\times\) \((\)字母 \(b\) 的数量的最小值\(+1)\) \(\times\cdots \times\) \((\)字母 \(z\) 的数量的最小值\(+1)\)。
总时间复杂度 \(O(n|C|2^n)\),其中 \(|C|\) 是字符集大小。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1 << 23, M = 20005, mod = 998244353;
int n, bit[N], f[N], l[26], len[24][26]; ll ans; char s[24][M];
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n;
for (int i = 0; i < n; ++ i) {
cin >> s[i];
for (int c = 'a', p = 0; c <= 'z'; ++ c)
while (s[i][p] == c) ++ p, ++ len[i][c - 'a'];
}
for (int i = 1; i < 1 << n; ++ i) {
f[i] = 1;
for (int c = 0; c < 26; ++ c) l[c] = 1e9;
for (int j = 0; j < n; ++ j) if (i >> j & 1)
for (int c = 0; c < 26; ++ c) l[c] = min(l[c], len[j][c]);
for (int c = 0; c < 26; ++ c) f[i] = (ll)f[i] * (l[c] + 1) % mod;
f[i] = mod - f[i];
}
for (int j = 0; j < n; ++ j)
for (int i = 0; i < 1 << n; ++ i)
if (i >> j & 1) (f[i] += mod - f[i ^ (1 << j)]) %= mod;
for (int i = 0; i < 1 << n; ++ i) {
int k = 0; ll sum = 0;
for (int j = 0; j < n; ++ j) if (i >> j & 1) ++ k, sum += j + 1;
bit[i] = bit[i >> 1] + (i & 1);
if (bit[i] & 1) f[i] = mod - f[i];
ans ^= (ll)f[i] * k * sum;
}
return cout << ans << '\n', 0;
}