AHOI2013 差异
\(SAM\)中比较简单的题.
题目链接
其实这道题有一种用时间换空间的\(SA\)做法.
就是把\(Height\)建出来之后从大到小做,用一个并查集记录\(size\)即可.
时间复杂度\(O(n*\log n)\),空间复杂度\(O(n)\)
\(SAM\)的话就枚举一个点,算一下有多少种方案可以使两个点的\(lca\)是它即可.
算出方案再乘上\(len\)就好了.
时间复杂度\(O(n)\),空间复杂度\(O(n*26)\)
代码如下
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define N (2000010)
#define M (N<<1)
#define inf (0x7f7f7f7f)
#define rg register int
#define Label puts("NAIVE")
#define spa print(' ')
#define ent print('\n')
#define rand() (((rand())<<(15))^(rand()))
typedef long double ld;
typedef long long LL;
typedef unsigned long long ull;
using namespace std;
char s[N]; int n; LL ans;
struct SAM{
int fa[N],ch[N][26],len[N],siz[N];
int lst,cnt,fi[N],ne[M],b[M],E;
SAM(){lst=cnt=1;}
void add(int x,int y){
ne[++E]=fi[x],fi[x]=E,b[E]=y;
}
void insert(int w,int L){
int u=lst;len[lst=++cnt]=L,siz[cnt]=1;
for(;u&&!ch[u][w];u=fa[u])ch[u][w]=cnt;
if(!u){fa[cnt]=1;return;}
int s=ch[u][w];
if(len[u]+1==len[s]){fa[cnt]=s;return;}
len[++cnt]=len[u]+1;
for(int i=0;i<26;i++)ch[cnt][i]=ch[s][i];
fa[cnt]=fa[s],fa[s]=fa[lst]=cnt;
for(int i=u;ch[i][w]==s;i=fa[i])ch[i][w]=cnt;
}
void build(){for(int i=2;i<=cnt;i++)add(fa[i],i);}
void solve(int u){
for(int i=fi[u];i;i=ne[i]){
int v=b[i]; solve(v);
ans+=1ll*siz[v]*siz[u]*len[u],siz[u]+=siz[v];
}
}
}S;
int main(){
scanf("%s",s+1),n=strlen(s+1);
for(int i=1;i<=n;i++)S.insert(s[i]-'a',i);
S.build(),S.solve(1);
printf("%lld\n",1ll*(n-1)*n*(n+1)/2-2*ans);
}