代码能力太弱。。想了5分钟写了1小时。。
耐下心来读完题,然后发现最优解一定是不会出现第一种情况的,也就是说如果访问一个串之前一定要访问这个串的所有后缀。
那么我们把串反过来,转换成前缀,也就是沿着trie走的问题。然后就贪心一波,先走子树小的再走子树大的就行了。
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
const int N=510005;
int n,cnt,dfn;
long long ans;
int id[N],fa[N],ch[N][26],size[N];
bool flag[N];
char s[N];
vector<pair<int,int> > a[N];
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline void add()
{
scanf("%s",s+1);
int len=strlen(s+1),c,now=0;
for (int i=len;i;i--)
{
c=s[i]-'a';
if (ch[now][c]) now=ch[now][c];
else now=ch[now][c]=++cnt;
}
size[now]=1;
}
void dfs(int x,int f)
{
id[x]=++dfn; ans+=id[x]-id[f];
for (int i=0;i<a[x].size();i++)
dfs(a[x][i].second,x);
}
void build(int x,int f)
{
if (size[x]) fa[x]=f,f=x;
for (int i=0;i<26;i++)
if (ch[x][i]) build(ch[x][i],f);
}
int main()
{
n=read();
for (int i=1;i<=n;i++) add();
build(0,0);
for (int x=cnt;x;x--)
if (size[x]) size[fa[x]]+=size[x],a[fa[x]].push_back(make_pair(size[x],x));
for (int x=0;x<=cnt;x++)
if (size[x]) sort(a[x].begin(),a[x].end());
dfn=-1;
dfs(0,0);
cout << ans << endl;
return 0;
}