洛谷传送门
BZOJ传送门
LOJ传送门
解析:
我们发现总是存在一种办法使得全程都不出现情况一。
而全程都不出现情况一,总贡献甚至不可能达到 n 2 n^2 n2。所以我们的策略就是绝不出现情况一。
然后考虑怎么给同一个串的后缀安排顺序。
转为给所有以这个串为后缀的串安排顺序。
显然“一个串是另一个串的后缀”这个关系是一个树形结构。
我们发现按照子树的siz从小到大处理就能同时最小化 2 2 2和 3 3 3的贡献。
把串翻转,后缀改成前缀,上Trie树就行了
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cout;
using std::cin;
cs int N=1e5+5,B=510005;
int n;
namespace Trie{
int rt,tot;
int son[B][26],id[B];
inline void insert(char *s,int pos){
int len=strlen(s),now=rt;
for(int re i=len-1;~i;--i){
int c=s[i]-'a';
if(!son[now][c])son[now][c]=++tot;
now=son[now][c];
}
id[now]=pos;
}
std::vector<int> e[N];
void build(int now,int fa){
if(id[now])e[fa].push_back(id[now]);
for(int re i=0;i<26;++i)
if(son[now][i])build(son[now][i],id[now]?id[now]:fa);
}
int siz[N];
inline bool cmp(cs int &a,cs int &b){return siz[a]<siz[b];}
void get_siz(int u){
siz[u]=1;
for(int re i=0;i<e[u].size();++i){
int v=e[u][i];
get_siz(v);
siz[u]+=siz[v];
}
sort(e[u].begin(),e[u].end(),cmp);
}
ll f[N];
ll dfs(int u){
f[u]=1;
ll tmp=0;
for(int re i=0;i<e[u].size();++i){
int v=e[u][i];
f[u]+=dfs(v)+tmp;
tmp+=siz[v];
}
return f[u];
}
inline void solve(){
build(rt,0);
get_siz(0);
cout<<(dfs(0)-1)<<"\n";
}
}
char s[B];
signed main(){
std::ios::sync_with_stdio(false);
cin>>n;
for(int re i=1;i<=n;++i){
cin>>s;
Trie::insert(s,i);
}
Trie::solve();
return 0;
}