差异[AHOI2013]
我们建SAM,在SAM上跑DP:(SAM不会点这里)
我们发现柿子的前半部分很好统计,那么我们只要搞后半部分。
我们反向建SAM,fa上的LCA就是其反串的前缀的后缀(原串的后缀的前缀)。
#include<bits/stdc++.h> #define N 1000017 #define deg using namespace std; struct S{ int val,ch[26],fa;}T[N]; int tot=1,last=1,np,q,nq,cnt[N],c[N>>1],len,id[N],x,sum[N]; char ch[N>>1]; long long ans; inline void Sam(int x){ np=++tot; T[np].val=T[last].val+1; for (;last&&!T[last].ch[x];last=T[last].fa) T[last].ch[x]=np; if (!last) T[np].fa=1; else { q=T[last].ch[x]; if (T[last].val+1==T[q].val) T[np].fa=q; else { nq=++tot; T[nq]=T[q];T[nq].val=T[last].val+1; T[q].fa=T[np].fa=nq; for (;last&&T[last].ch[x]==q;last=T[last].fa) T[last].ch[x]=nq; } } last=np; sum[last]=cnt[last]=1; } int main () { // freopen("a.in","r",stdin); scanf("%s",ch+1); len=strlen(ch+1); for (int i=len;i;i--) Sam(ch[i]-'a'); for (int i=1;i<=tot;i++) c[T[i].val]++; for (int i=1;i<=len;i++) c[i]+=c[i-1]; for (int i=1;i<=tot;i++) id[c[T[i].val]--]=i; for (int i=tot;i;i--) cnt[T[id[i]].fa]+=cnt[id[i]]; for (int i=tot;i;i--) { x=id[i]; ans+=1ll*sum[T[x].fa]*cnt[x]*T[T[x].fa].val; sum[T[x].fa]+=cnt[x]; } deg("%lld\n",ans); printf("%lld\n",1ll*len*(len-1)*(len+1)/2-ans*2); return 0; }