码迷,mamicode.com
首页 > 其他好文 > 详细

[SPOJ705]不同的子串

时间:2018-01-12 22:40:06      阅读:187      评论:0      收藏:0      [点我收藏+]

标签:int   out   scan   style   div   printf   target   pen   c++   

题目点这里

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

我们发现后缀自动机每条路径代表一条子串,那么我们就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]不同的子串

标签:int   out   scan   style   div   printf   target   pen   c++   

原文地址:https://www.cnblogs.com/rrsb/p/8277736.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!