CF1902E. Collapsing Strings-LCP、字典树
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;
}