SPOJ705 SPOJ694 Distinct Substrings SAM
阿新 • • 發佈:2018-12-07
題意:
給你一個字串,問你有多少個本質不同的字串。其中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;
}