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";
}
posted on 2024-04-02 21:17  Bubble_e  阅读(15)  评论(0)    收藏  举报