zoukankan      html  css  js  c++  java
  • POJ 3882/LA4513/HDU4080/ZOJ3395 Stammering Aliens 题解【后缀自动机】

    题意:求一个串中可重叠至少出现m次的最长子串,并且求出该串最后一次出现的起始位置。

    找了一下网上并没有SAM做法的题解。。我来说一下好了 

    首先每个SAM上的结点需要多保存两个值:cnt和right。cnt代表该状态right集合大小,right值是right集合中最大的那个值(right集合定义见CLJ ppt),初值为val。

    其实结点如果是复制的结点(即代码中nq)的话初值应该是原结点的right?。。没关系,我们总会更新到的

    那么我们就有了两种做法:1、每次插入完暴力往上更新父亲结点的right集合大小。

    2、插入完之后统一更新(如SPOJ 8222)

    第一种做法是有问题的,复杂度得不到保证,于是妥妥TLE。

    第二种相对比较麻烦。。由于val值大的可以更新val值小的cnt,那么先根据val值进行一次排序。然后因为所有子串都是某个前缀的某个后缀,那么我们把前缀的cnt设置为1(从网上讲解的图来看,就是最中间那一排结点cnt值全部设置为1,其它设置为0),按照val从大到小更新一下cnt和right即可。

    怕跪掉所以对m=1进行了特判。。其实不特判也是可以的

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 const int MAXN=40000+5;
     5 const int SIGMA_SIZE=26;
     6 const int INF=~0U>>1;
     7 struct State{
     8     State* go[SIGMA_SIZE],*suf;
     9     int val,cnt,right;
    10     State():suf(0) {val=cnt=0;memset(go,0,sizeof go);}
    11 }*root,*last;
    12 State mem[MAXN<<1],*cur;
    13 int ans1,ans2;
    14 int m;
    15 inline void init()
    16 {
    17     ans1=-1;
    18     cur=mem;
    19     mem[0]=State();
    20     last=root=cur++;
    21 }
    22 inline void extend(int w)
    23 {
    24     State* p=last,*np=cur++;
    25     *np=State();
    26     np->right=np->val=p->val+1;
    27     while(p && !p->go[w]) p->go[w]=np,p=p->suf;
    28     if(!p) np->suf=root;
    29     else
    30     {
    31         State* q=p->go[w];
    32         if(q->val==p->val+1) np->suf=q;
    33         else
    34         {
    35             State* nq=cur++;
    36             *nq=State();
    37             memcpy(nq->go,q->go,sizeof q->go);
    38             nq->right=nq->val=p->val+1;
    39             nq->suf=q->suf;
    40             q->suf=np->suf=nq;
    41             while(p && p->go[w]==q) p->go[w]=nq,p=p->suf;
    42         }
    43     }
    44     last=np;
    45 }
    46 inline int idx(char c)
    47 {
    48     return c-'a';
    49 }
    50 char s[MAXN];
    51 int n;
    52 State* pt[MAXN<<1];
    53 void work()
    54 {
    55     static int ws[MAXN<<1];
    56     State* t;
    57     for(int i=0;i<=n;++i) ws[i]=0;
    58     for(t=mem+1;t!=cur;++t) ++ws[t->val];
    59     for(int i=1;i<=n;++i) ws[i]+=ws[i-1];
    60     for(t=cur-1;t!=mem;--t) pt[--ws[t->val]]=t;
    61     t=root;
    62     for(int i=0;i<n;++i) t=t->go[idx(s[i])],t->cnt++;
    63     for(int i=cur-mem-2;i>=0;--i)
    64     {
    65         State* u=pt[i];
    66         if(u->cnt>=m)
    67         {
    68             if(u->val>ans1) ans1=u->val,ans2=u->right-u->val;
    69             else if(u->val==ans1) ans2=std::max(ans2,u->right-u->val);
    70         }
    71         if(u->suf)
    72             u->suf->cnt+=u->cnt,u->suf->right=std::max(u->suf->right,u->right);
    73     }
    74 }
    75 int main()
    76 {
    77     //freopen("1.in","r",stdin);
    78     while(scanf("%d",&m)!=EOF && m)
    79     {
    80         init();
    81         scanf("%s",s);
    82         n=strlen(s);
    83         if(m==1)
    84         {
    85             printf("%d 0
    ",n);
    86             continue;
    87         }
    88         for(int i=0;i<n;++i)
    89             extend(idx(s[i]));
    90         work();
    91         if(ans1==-1) puts("none");
    92         else printf("%d %d
    ",ans1,ans2);
    93     }
    94     return 0;
    95 }
    View Code
  • 相关阅读:
    c# 生成随机时间
    HttpWebRequest.ReadWriteTimeout 属性
    如果分配给命令的连接位于本地挂起事务中,ExecuteNonQuery 要求命令拥有事务。命令的 Transaction 属性尚未初始化
    Host 'XXX' is not allowed to connect to this MySQL server 解决方案/如何开启MySQL的远程帐号
    C# winform 获取当前路径
    c# 操作符重载
    为何好男人总被坏女人搞定?【转】
    MySQL,SQLSERVER,ORACLE获取数据库表名及字段名
    病毒加壳技术与脱壳杀毒方法解析
    配置linux DNS
  • 原文地址:https://www.cnblogs.com/lowsfish/p/4424594.html
Copyright © 2011-2022 走看看