题意是问给定字符串中出现超过一次的不同子串有多少个。
显然可以用后缀自动机来搞。知道自动机中后缀转移的性质,不难实现沿fail指针统计不同子串个数。
#include<cstdio>
#pragma GCC optimize ("O2")
#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
#include<cassert>
using namespace std;
typedef long long LL;
int opt[256];
const int N = 1e5+7;
const int MAX=2e5+7;
const int NUM=64;
const char BASE=0;
struct node{
node *ch[NUM];
node *fa;
int len,num,hash;
//int end;
node(){}
node(node* father,int lenth){
fa=father;
len=lenth;
num=0;
//end=0;
hash=0;
memset(ch,0,sizeof ch);
}
};
struct SAM{
node tree[MAX],*Root,*p; //private
int cnt, len; //private
char a[MAX]; //record the string
int ws[MAX];node *hh[MAX]; //used for sort
int distinctsubstring; //the total number of distinct strings;
void init(){
cnt = len = 0;
distinctsubstring = 0;
p=Root=tree+(cnt++);
*Root=node(0,0);
}
inline void add(char c){
node *np,*op,*cp;
int idx = opt[c];
np=tree+(cnt++);
*np=node(0,len+1);
np->num=1;
//np->end=len;
while(p && !p->ch[idx]) p->ch[idx]=np, p=p->fa;
if(p && p->ch[idx]){
op=p->ch[idx];
if(p->len+1==op->len) np->fa=op;
else{
cp=tree+(cnt++);
*cp=*op;
cp->len=p->len+1;
cp->num=0;
//cp->end=len;
op->fa=cp;
np->fa=cp;
while(p && p->ch[idx]==op) p->ch[idx]=cp, p=p->fa;
}
}
else np->fa=Root;
p=np;
a[len++] = c;
//distinctsubstring += np->len - np->fa->len;
}
void sort(){
memset(ws, 0, sizeof(int)*(cnt+2) );
for(int i=0;i<cnt;++i) ws[tree[i].len+1]++;
for(int i=0;i<cnt;++i) ws[i+1] += ws[i];
for(int i=0;i<cnt;++i) hh[ ws[tree[i].len]++ ]=tree+i;
for(int i=cnt-1; i>=1; --i){
if(!hh[i]->fa)continue;
hh[i]->fa->num += hh[i]->num;
}
}
int fuck( ){
int sum=0;
for (int i=1; i<cnt; i++){
if ( hh[i]->num>1 )
sum += hh[i]->len - hh[i]->fa->len;
}
return sum;
}
};
SAM s;
char str[N];
int main(){
//freopen("E:\\file.in","r",stdin);
//freopen("E:\\file.out","w",stdout);
for (int i=0; i<26; i++) opt['a'+i]=i;
for (int i=0; i<26; i++) opt['A'+i]=i+26;
for (int i=0; i<10; i++) opt['0'+i]=i+52;
opt['.']=62, opt[',']=63;
while ( gets(str) && (!(str[0]=='*' && strlen(str)==1 )) ){
s.init();
for (int i=0; str[i]; i++) {
s.add( str[i] );
}
s.sort();
printf("%d\n", s.fuck() );
}
return 0;
}