CF1902E. Collapsing Strings-LCP、字典樹

yoshinow2001發表於2024-05-09

link:https://codeforces.com/contest/1902/problem/E

題意:You are given \(n\) strings \(s_1, s_2, \dots, s_n\), consisting of lowercase Latin letters. Let \(|x|\) be the length of string \(x\). Let a collapse \(C(a, b)\) of two strings \(a\) and \(b\) be the following operation:

  • if \(a\) is empty, \(C(a, b) = b\); - if \(b\) is empty, \(C(a, b) = a\);
  • if the last letter of \(a\) is equal to the first letter of \(b\), then \(C(a, b) = C(a_{1,|a|-1}, b_{2,|b|})\), where \(s_{l,r}\) is the substring of \(s\) from the \(l\)-th letter to the \(r\)-th one;
  • otherwise, \(C(a, b) = a + b\), i. e. the concatenation of two strings.
    Calculate \(\sum\limits_{i=1}^n \sum\limits_{j=1}^n |C(s_i, s_j)|\).

\(\sum |s_i|\leq 10^6\).


\(C(s,t)=|s|+|t|-2\times LCP(t,s')\),其中 \(s'\) 表示 \(s\) 的反串, \(LCP\) 表示最長公共字首。

因此 $$ans=\sum_{i=1}n\sum_{j=1}n |s_i|+|s_j|-2 LCP(s_j,s_i')=2n\cdot\sum_{i=1}n|s_i|-2\sum_{i=1}n\sum_{j=1}^n LCP(s_i',s_j)$$
對於後者,列舉每個 \(s_i'\) ,查詢其和所有其他串最長公共字首,將所有串插入到字典樹上,做一個子樹查詢即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
const int N=1e6+5;
const int C=26;
int n,tr[N][C+1],tag[N],cnt;
string s[N];
void insert(const string &s){
    int len=s.length(),k=0;
    for(int i=0;i<len;i++){
        int ch=s[i]-'a';
        if(!tr[k][ch])tr[k][ch]=++cnt;
        k=tr[k][ch];
        tag[k]++;
    }
}
ll work(const string &s){
    int len=s.length(),k=0;
    ll ret=0;
    for(int i=len-1;i>=0;i--){
        int ch=s[i]-'a';
        k=tr[k][ch];
        if(!k)break;
        ret+=tag[k];
    }
    return ret;
}
int main(){
    fastio;
    cin>>n;
    ll ans=0;
    rep(i,1,n){
        cin>>s[i];
        insert(s[i]);
        ans+=(ll)2*n*s[i].length();
    }
    rep(i,1,n)ans-=2*work(s[i]);
    cout<<ans;
    return 0;
}

相關文章