1. 程式人生 > >SPOJ705 SPOJ694 Distinct Substrings SAM

SPOJ705 SPOJ694 Distinct Substrings SAM

SPOJ705
SPOJ694

題意:
給你一個字串,問你有多少個本質不同的字串。其中SPOJ705是加強版,20組詢問,每組n<=50000。

題解:
這個題異常坑爹!!!我調這個題調了一上午,心態爆炸。這個加強版沒有說字符集大小,我以為是26,結果發現不是!

迴歸正題,這個題的做法其實就是建出SAM,然後對於每個點,用它的串長減去parent樹上它父節點的串長就行了,這樣就可以不重不漏的計數了。

程式碼:

#include <bits/stdc++.h>
using namespace std;

int T,n,fa[2000010],ch[100010][100],len[
2000010],cnt=1,rt=1,lst=1; long long ans; char s[1000010]; inline void insert(int x) { int cur=++cnt,pre=lst; lst=cur; len[cur]=len[pre]+1; for(;pre&&!ch[pre][x];pre=fa[pre]) ch[pre][x]=cur; if(!pre) fa[cur]=rt; else { int ji=ch[pre][x]; if(len[ji]==len[pre]+1) fa[cur]=ji; else { int
gg=++cnt; len[gg]=len[pre]+1; memcpy(ch[gg],ch[ji],sizeof(ch[ji])); fa[gg]=fa[ji]; fa[ji]=fa[cur]=gg; for(;pre&&ch[pre][x]==ji;pre=fa[pre]) ch[pre][x]=gg; } } } int main() { scanf("%d",&T); while(T--) { cnt=1,rt=1,lst=1; ans=0; scanf("%s",s+1); n=strlen(
s+1); for(int i=1;i<=n;++i) insert(s[i]-'A'); for(int i=1;i<=cnt;++i) ans+=len[i]-len[fa[i]]; for(int i=0;i<=cnt;++i) { fa[i]=len[i]=0; memset(ch[i],0,sizeof(ch[i])); } printf("%lld\n",ans); } return 0; }