题意
给出一个只含小写字母的串
s
,求
|s|≤1000000
题解
SAM
最水的模板题。
直接建出
SAM
,把所有状态的
max(A)−min(A)+1
全部加起来即是答案。应该不需要解释。
实现的话可以在
Extend
过程中维护,这样写比较有价值,最后扫一趟太丑啦…
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000005;
struct node{
node *par,*ch[26]; int _max;
node(int t1=0){ _max=t1; par=0; memset(ch,0,sizeof(ch)); }
int cnt(){ return _max-par->_max; }
} *root, *last;
typedef node* P_node;
long long ans;
void Extend(char x){
P_node p=last, np=new node(p->_max+1);
while(p&&p->ch[x]==0) p->ch[x]=np, p=p->par;
if(!p) np->par=root; else{
P_node q=p->ch[x];
if(q->_max==p->_max+1) np->par=q; else{
P_node nq=new node(p->_max+1);
memcpy(nq->ch,q->ch,sizeof(q->ch));
ans-=q->cnt(); //*
nq->par=q->par; q->par=nq; np->par=nq;
ans+=q->cnt()+nq->cnt(); //*
while(p&&p->ch[x]==q) p->ch[x]=nq, p=p->par;
}
}
ans+=np->cnt(); //*
last=np;
}
char s[maxn];
int n;
int main(){
freopen("hiho1445.in","r",stdin);
freopen("hiho1445.out","w",stdout);
scanf("%s",s+1); n=strlen(s+1);
root=last=new node(0);
for(int i=1;i<=n;i++) Extend(s[i]-'a');
printf("%lld\n",ans);
return 0;
}