【51nod1469】淋漓尽致子串

  • 本文为博主原创,未经许可不得转载

首先建立后缀自动机,然后对于每个状态:

如果他的size为1,则这个状态不合法

如果他能转移到一个size>1的状态,那么这个状态也不合法

如果他在parent树上有一个size>1的孩子,那么这个状态也不合法

剩下的就是合法的,统计合法状态的数量就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<bits/stdc++.h>
#define FILE "read"
#define MAXN 200010
using namespace std;
int n,ans,now(1),cnt(1),c[MAXN],id[MAXN],mx[MAXN],par[MAXN],Right[MAXN],vis[MAXN],son[MAXN][26];
char ch[MAXN];
void extend(int x){
int np=++cnt,p=now;
mx[np]=mx[p]+1; now=np; Right[np]=1;
while(!son[p][x]&&p) son[p][x]=np,p=par[p];
if(!p) par[np]=1;
else{
int q=son[p][x];
if(mx[q]==mx[p]+1) par[np]=q;
else{
int nq=++cnt; mx[nq]=mx[p]+1;
memcpy(son[nq],son[q],sizeof(son[q]));
par[nq]=par[q]; par[q]=par[np]=nq;
while(son[p][x]==q&&p) son[p][x]=nq,p=par[p];
}
}
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
scanf("%s",ch+1); n=strlen(ch+1);
for(int i=1;i<=n;++i) extend(ch[i]-'a');
for(int i=1;i<=cnt;++i) c[mx[i]]++;
for(int i=1;i<=n;++i) c[i]+=c[i-1];
for(int i=1;i<=cnt;++i) id[c[mx[i]]--]=i;
for(int i=cnt;i;--i) Right[par[id[i]]]+=Right[id[i]]; Right[0]=0;
for(int i=cnt;i;--i) if(Right[id[i]]>1||vis[id[i]]) vis[par[id[i]]]=1;
for(int i=1;i<=cnt;++i) if(Right[i]<=1) vis[i]=1;
for(int i=1;i<=cnt;++i)for(int j=0;j<26;++j)if(Right[son[i][j]]>1)vis[i]=1;
for(int i=2;i<=cnt;++i)if(!vis[i])ans++;
printf("%d\n",ans);
return 0;
}
文章目录
,