思路:編輯我們可以發現兩個字串的最長公共字首就是字典樹中的最近公共祖先。然而這道題,比如說某個結點是x個字串的字首,那麼當前結點對答案的貢獻為x * (x - 1) / 2,就是x中任選兩個字串組合,因為在這之前,這些字串的字首在計算其他結點的時候已經被算過了。
程式碼:
#define ll long long
#define N 300010
using namespace std;
ll n,ch[N][26],sz[N];
int main(){
ll i,x,tot=1;
cin>>n;
while(n--)
{
string s;
cin>>s;
for(i=0,x=1;i<s.size();i++)
{
sz[x]++;
if(!ch[x][s[i]-'a'])
{
ch[x][s[i]-'a']=++tot;
}
x=ch[x][s[i]-'a'];
}
sz[x]++;
}
ll ans=0;
for(i=2;i<=tot;i++)
{
ans+=sz[i]*(sz[i]-1)/2;
}
cout<<ans<<'\n';
return 0;
}
