[SPOJ705]不同的子串

Posted 殇雪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SPOJ705]不同的子串相关的知识,希望对你有一定的参考价值。

题目点这里

我们发现这道题可以用后缀自动机做(不会的点这里

我们发现后缀自动机每条路径代表一条子串,那么我们就DP:

写法一

#include<bits/stdc++.h>
#define N 100071
using namespace std;
struct Node{
    int c[26],fa,val;
}T[N];
int tot=1,last=1,D[N],c[N],np,q,nq,len,id[N],ans;
char ch[N];
inline void Sam(int x){
    np=++tot; T[np].val=T[last].val+1;
    for (;last&&!T[last].c[x];last=T[last].fa) T[last].c[x]=np;
    if (!last) T[np].fa=1;
    else { q=T[last].c[x];
     if (T[q].val==T[last].val+1) T[np].fa=q;
     else  {
         nq=++tot; T[nq]=T[q];
         T[nq].val=T[last].val+1; T[np].fa=T[q].fa=nq;
         for (;last&&T[last].c[x]==q;last=T[last].fa) T[last].c[x]=nq;
     }
    } last=np; 
}
int main () {
    freopen("subst1.in","r",stdin);
    freopen("subst1.out","w",stdout);
    scanf("%s",ch+1);len=strlen(ch+1);
    for (int i=1;i<=len;i++)
     Sam(ch[i]-\'A\');
    for (int i=1;i<=tot;i++) c[T[i].val]++,D[i]=1;
    for (int i=1;i<=len;i++) c[i]+=c[i-1];
    for (int i=1;i<=tot;i++) id[c[T[i].val]--]=i;
    for (int i=tot;i;i--) 
     for (int j=0;j<26;j++)
      D[id[i]]+=D[T[id[i]].c[j]];
    printf("%d\\n",D[1]-1); 
//    for (int i=tot;i;i--) ans+=T[i].val-T[T[i].fa].val;
//    printf("%d\\n",ans);
    return 0;
}

我们可以把DP方程化简一下,得到写法二

#include<bits/stdc++.h>
#define N 100071
using namespace std;
struct Node{
    int c[26],fa,val;
}T[N];
int tot=1,last=1,D[N],c[N],np,q,nq,len,id[N],ans;
char ch[N];
inline void Sam(int x){
    np=++tot; T[np].val=T[last].val+1;
    for (;last&&!T[last].c[x];last=T[last].fa) T[last].c[x]=np;
    if (!last) T[np].fa=1;
    else { q=T[last].c[x];
     if (T[q].val==T[last].val+1) T[np].fa=q;
     else  {
         nq=++tot; T[nq]=T[q];
         T[nq].val=T[last].val+1; T[np].fa=T[q].fa=nq;
         for (;last&&T[last].c[x]==q;last=T[last].fa) T[last].c[x]=nq;
     }
    } last=np; 
}
int main () {
    freopen("subst1.in","r",stdin);
    freopen("subst1.out","w",stdout);
    scanf("%s",ch+1);len=strlen(ch+1);
    for (int i=1;i<=len;i++)
     Sam(ch[i]-\'A\');
//    for (int i=1;i<=tot;i++) c[T[i].val]++,D[i]=1;
//    for (int i=1;i<=len;i++) c[i]+=c[i-1];
//    for (int i=1;i<=tot;i++) id[c[T[i].val]--]=i;
//    for (int i=tot;i;i--) 
//     for (int j=0;j<26;j++)
//      D[id[i]]+=D[T[id[i]].c[j]];
//    printf("%d\\n",D[1]-1); 
    for (int i=tot;i;i--) ans+=T[i].val-T[T[i].fa].val;
    printf("%d\\n",ans);
    return 0;
}

 

以上是关于[SPOJ705]不同的子串的主要内容,如果未能解决你的问题,请参考以下文章

SPOJ 705 Distinct Substrings(后缀数组)

SPOJ694&705Distinct Substrings(后缀数组)

SPOJ705-New Distinct Substrings-后缀数组

SPOJ 694 不同子串个数

SPOJ SUBLEX Lexicographical Substring Search - 后缀数组

[spoj DISUBSTR]后缀数组统计不同子串个数