AT_abc343_g [ABC343G] Compress Strings

思路

首先假设有两个串 a,ba,b,如果 bbaa 的子串,且 aba \neq b 则不需要考虑 bb;如果 a=ba = b,则如需要保留一个 aa

做完上述操作后,显然最终的答案是由这些串按照一定顺序拼接起来,再删掉重叠部分。

例如:abbccccdde 拼接为 abbccccdde,发现 cc 是重复的,所以删掉重叠部分为 abbccde

显然我们可以使用 KMP 在 Θ(n2S)\Theta(n^2 \cdot |S|) 的复杂度内求解出任意两个串 si,sjs_i,s_j 的重叠部分,记作 numi,jnum_{i,j}

于是就变成了经典状压,我们定义 dpst,idp_{st,i} 表示选取串的集合表示为 stst,且最后选的一个串为 sjs_j

然后就是经典状压转移了。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <bits/stdc++.h>
#define re register

using namespace std;

const int N = 24,M = 4e5 + 10,K = (1 << 20) + 10,inf = 0x3f3f3f3f;
int n,m,ans = inf;
int nxt[M],len[N];
int num[N][N],dp[K][N];
string t[N],s[N];
unordered_map<string,bool> vis;

inline int kmp(string a,string b){
string s = a + '&' + b; int len = s.length();
for (re int i = 0;i < len;i++) nxt[i] = 0;
for (re int i = 1,j = 0;i < len;i++){
while (j && s[i] != s[j]) j = nxt[j - 1];
if (s[i] == s[j]) j++;
nxt[i] = j;
}
return nxt[len - 1];
}

int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
memset(dp,inf,sizeof(dp));
cin >> n;
for (re int i = 1;i <= n;i++) cin >> t[i];
for (re int i = 1;i <= n;i++){
for (re int j = 1;j <= n;j++){
if (i == j) continue;
if (t[j].find(t[i]) != string::npos && t[i] != t[j]) goto End;
}
if (vis.count(t[i])) continue;
vis[t[i]] = true;
s[++m] = t[i]; len[m] = t[i].length();
End:;
}
n = m;
for (re int i = 1;i <= n;i++){
for (re int j = 1;j <= n;j++){
if (i != j) num[i][j] = kmp(s[j],s[i]);
}
}
for (re int st = 1;st < (1 << n);st++){
int cnt = __builtin_popcount(st);
if (cnt == 1){
int x;
for (re int i = 0;i < n;i++){
if ((st >> i) & 1){
x = i + 1; break;
}
}
dp[st][x] = len[x];
}
for (re int i = 0;i < n;i++){
if (!((st >> i) & 1)) continue;
for (re int j = 0;j < n;j++){
if ((st >> j) & 1) continue;
dp[st | (1 << j)][j + 1] = min(dp[st | (1 << j)][j + 1],dp[st][i + 1] + len[j + 1] - num[i + 1][j + 1]);
}
}
}
for (re int i = 1;i <= n;i++) ans = min(ans,dp[(1 << n) - 1][i]);
printf("%d\n",ans);
return 0;
}

AT_abc343_g [ABC343G] Compress Strings
http://watersun.top/[题解]AT_abc343_g [ABC343G] Compress Strings/
作者
WaterSun
发布于
2024年3月4日
许可协议