差异[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;
}

 

 

 

posted @ 2018-01-21 20:11  泪寒之雪  阅读(161)  评论(0编辑  收藏  举报