[ABC343G] Compress Strings

Captainfly19發表於2024-04-24

題目連結:https://www.luogu.com.cn/problem/AT_abc343_g

solution:
1.首先我們將給出的字串中互相包含的消去,可以使用kmp求前字尾來完成。和這道題的寫法一樣https://www.luogu.com.cn/problem/CF1200E
2.我們發現給出的字串最多隻有20個,考慮狀壓來求解所有可能
3.我們注意到這道題只需要求出最小的長度即可,那麼轉移的代價就是後面拼接上去的字串的有效長度。何為有效長度:因為兩個字串相接,有可能在前一個串的字尾和後一個串的字首會出現重疊,有效長度就是後一個串的長度減去重複的這部分得到的長度。
4.開始轉移 我們設dp[state][j] state為當前的選中的字串(目前得到的母串)構成的集合,j是當前的母串以第 j 個字串結尾 ,如此得到的母串長度。
5.轉移,具體操作見程式碼。


vector<int> kmp(string s)
{
    int n=s.size();
    vector<int> nxt(n+1);
    for(int i=1,j=0;i<n;i++)
    {
        while(j&&s[i]!=s[j])
        {
            j=nxt[j];
        }
        j+=(s[i]==s[j]);
        nxt[i+1]=j;
    }
    return nxt;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n;
    cin>>n;
    vector<string> S(n);
    for(int i=0;i<n;i++)
    {
        cin>>S[i];
    }
    vector<string> tmp;
    sort(all(S),[&](string a,string b){
        return a.size()<b.size();
    });
    for(int i=0;i<n;i++)
    {
        int flag=1;
        for(int j=i+1;j<n;j++)
        {
            vector<int> f=kmp(S[i]+'#'+S[j]);
            if(find(all(f),S[i].size())!=f.end())
            {
                flag=0;
                break;
            }
        }
        if(flag)
        {
            tmp.push_back(S[i]);
        }
    }
    n=tmp.size();
    S=tmp;
    vector cost(n,vector<int> (n));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==j) continue;
            vector<int> f=kmp(S[j]+'#'+S[i]);
            cost[i][j]=S[j].size()-f.back();
        }
    }
    vector dp((1<<n),vector<int> (n,1e9));
    vector<string> res(1<<n);
    for(int i=0;i<n;i++)
    {
        dp[1<<i][i]=S[i].size();
    }
    for(int s=1;s<(1<<n);s++)
    {
        for(int i=0;i<n;i++)
        {
            if(s>>i&1)
            {
                for(int j=0;j<n;j++)
                {
                    if(!(s>>j&1))
                    {
                        dp[s|1<<j][j]=min(dp[s|1<<j][j],dp[s][i]+cost[i][j]);
                    }
                }
            }
        }
    }
    int ans=*min_element(dp.back().begin(),dp.back().end());
    cout<<ans<<'\n';
}

相關文章