abc 343
G Compress Strings
思路
-
一眼状压(n 只有 20)
-
分类讨论
- 如果 \(s[i]\) 包含了 \(s[j]\), 就没有 \(s[j]\) 什么事了
- 否则考虑 \(i\) 加到 \(j\) 后面和反过来的代价
- 就是求 \(i + j\) 的 border
-
上述两个过程都可以 KMP 解决
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int M = 1.5e6 + 10;
const int N = 25;
int n;
int nxt[M], dp[M][N];
int cost[N][N], si;
string s[N];
set <int> str;
int Kmp(string s){
for(int i = 0; i < s.size(); i++){
nxt[i] = 0;
}
int j = 0;
for(int i = 1; i < s.size(); i++){
while(j && s[i] != s[j]){
j = nxt[j - 1];
}
if(s[i] == s[j]){
j++;
}
nxt[i] = j;
if(nxt[i] == si){
return si;
}
}
return nxt[s.size() - 1];
}
signed main(){
// freopen("1.in", "r", stdin);
cin >> n;
for(int i = 1; i <= n; i++){
cin >> s[i];
str.insert(i);
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(s[i].size() > s[j].size() || i == j || str.find(j) == str.end()){
continue;
}
si = s[i].size();
if(s[i].size() == Kmp(s[i]+'#'+s[j])){
// cout << i << "i ";
str.erase(i);
}
}
}
memset(dp, 0x3f3f3f3f, sizeof(dp));
int cnt = 0;
si = -1;
for(auto i : str){
for(auto j : str){
int ret = s[j].size() - Kmp(s[j]+"#"+s[i]);
cost[i][j] = ret;
}
dp[1<<cnt][cnt] = s[i].size();
cnt++;
}
int up = (1 << str.size()) - 1;
for(int i = 0; i <= up; i++){
int cnt = 0;
for(auto j : str){
if(!((i >> cnt) & 1)){
++cnt;
continue;
}
int cntt = 0;
for(auto k : str){
if((i >> cntt) & 1){
cntt++;
continue;
}
dp[i|(1<<cntt)][cntt] = min(dp[i|(1<<cntt)][cntt], dp[i][cnt] + cost[j][k]);
cntt++;
}
++cnt;
}
}
int mini = (int)1e18;
for(int i = 0; i < str.size(); i++){
// cout << dp[up][i] << " ";
mini = min(mini, dp[up][i]);
}
cout << mini << "\n";
}
浙公网安备 33010602011771号