zoukankan      html  css  js  c++  java
  • 【spoj8222-Substrings】sam求子串出现次数

    http://acm.hust.edu.cn/vjudge/problem/28005

    题意:给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值。求F(1)..F(Length(S)) 。

    题解:

    关键问题在于统计某个串出现了多少次。 

    在后缀自动机中,答案即为包含了这个串的状态的right集合的大小。 
    后缀自动机有两张DAG,一张是trans图,一张是parent树 
    从trans图的角度出发,right集合的大小为该状态走到结束状态的方案数 
    从parent树的角度出发,parent树是反串的后缀树,right集合的大小为该状态的子树中有多少个结点代表了反串的一个后缀(也就是原串的前缀) 
    我们采取第二种计数方法,先将包含原串前缀的状态的right集合设为1(相当于在反串的后缀树中将后缀结点标记为1) 
    因为parent树中我们并没有把儿子记下来,所以没办法直接对parent树bfs,但我们知道儿子的len严格大于父亲的len,所以我们按len的长度进行排序,然后按len从大到小,用当前点更新parent的答案 
    我们发现一个结点代表的长度是一个区间,我们先只考虑该结点代表的最长长度,然后我们再用长串去更新短串(因为一个长串出现k次,它的所有后缀都至少出现k次)即可

    ————引用自http://blog.csdn.net/hbhcy98/article/details/51055733

    首先要求节点x表示的最长的子串,也就是长度为step[x]的这个串出现了多少次——该节点的right集合。

    right集合到底怎么求?

    从parent树的角度出发,parent树是反串的后缀树,right集合的大小为该状态的子树中有多少个结点代表了反串的一个后缀(也就是原串的前缀)

    在建好的自动机上跑一遍原串,经过的节点r[x]=1;

    然后找出自动机的拓扑序,按着拓扑序的逆序for一遍,更新pre[x]。

    一个节点贡献的子串长度区间是[min[x],max[x]],我们开始只考虑了该节点代表的最大长度max[x],也就是长度为step[x]这个子串。

    然后我们用长串去更新短串。

    因为sam是在线的,从root开始跳到x节点的路径必定是主链上root到x这条最长串(原串的前缀)的后缀。

    一个长串出现k次,它的所有后缀都至少出现k次。

    f[i-1]=maxx(f[i-1],f[i]);

    机智啊。。。。。。我看了好几个题解才看懂。。。。TAT。。。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<queue>
     6 #include<ctime>
     7 using namespace std;
     8 
     9 const int N=2*250010;
    10 char s[N];
    11 int tot,last,sl,cl;
    12 int son[N][30],pre[N],step[N],in[N],c[N],r[N],f[N];
    13 bool vis[N];
    14 queue<int> Q;
    15 
    16 int maxx(int x,int y){return x>y ? x:y;}
    17 
    18 int add_node(int x){step[++tot]=x;/*r[tot]=1;*/return tot;}
    19 
    20 void clear()
    21 {
    22     memset(r,0,sizeof(r));
    23     memset(son,0,sizeof(son));
    24     memset(pre,0,sizeof(pre));
    25     memset(step,0,sizeof(step));
    26     tot=0;add_node(0);last=1;
    27 }
    28 
    29 void extend(int ch)
    30 {
    31     int p=last,np=add_node(step[p]+1);
    32     while(p && !son[p][ch]) son[p][ch]=np,in[np]++,p=pre[p];
    33     if(!p) pre[np]=1;
    34     else
    35     {
    36         int q=son[p][ch];
    37         if(step[q]==step[p]+1) pre[np]=q;
    38         else
    39         {
    40             int nq=add_node(step[p]+1);
    41             memcpy(son[nq],son[q],sizeof(son[q]));
    42             for(int i=1;i<=26;i++) 
    43                 if(son[q][i]) in[son[q][i]]++;
    44             pre[nq]=pre[q];
    45             pre[np]=pre[q]=nq;
    46             while(son[p][ch]==q) son[p][ch]=nq,in[nq]++,in[q]--,p=pre[p];
    47         }
    48     }
    49     last=np;
    50 }
    51 
    52 void find_tp()
    53 {
    54     while(!Q.empty()) Q.pop();
    55     memset(vis,0,sizeof(vis));
    56     Q.push(1);vis[1]=1;cl=0;
    57     while(!Q.empty())
    58     {
    59         int x=Q.front();vis[x]=0;c[++cl]=x;Q.pop();
    60         for(int i=1;i<=26;i++)
    61         {
    62             int y=son[x][i];
    63             if(!y) continue;
    64             in[y]--;
    65             if(!in[y] && !vis[y]) vis[y]=1,Q.push(y);
    66         }
    67     }
    68 }
    69 
    70 int main()
    71 {
    72     freopen("a.in","r",stdin);
    73     scanf("%s",s+1);
    74     sl=strlen(s+1);
    75     clear();
    76     for(int i=1;i<=sl;i++) extend(s[i]-'a'+1);
    77     int x=1,ch;
    78     for(int i=1;i<=sl;i++)
    79     {
    80         ch=s[i]-'a'+1;
    81         x=son[x][ch];
    82         r[x]++;
    83     }
    84     find_tp();
    85     for(int i=cl;i>=1;i--)
    86     {
    87         x=c[i];
    88         r[pre[x]]+=r[x];
    89         // printf("r %d  =  %d  step = %d
    ",x,r[x],step[x]);
    90         f[step[x]]=maxx(f[step[x]],r[x]);
    91     }
    92     // for(int i=1;i<=sl;i++) printf("%d ",f[i]);printf("
    ");
    93     for(int i=sl;i>=2;i--) f[i-1]=maxx(f[i],f[i-1]);
    94     for(int i=1;i<=sl;i++) printf("%d
    ",f[i]);
    95     return 0;
    96 }
  • 相关阅读:
    IOS 修改UIAlertController的按钮标题的字体颜色,字号,内容
    UITableView heightForHeaderInSection遇到的坑
    .19-浅析webpack源码之compile流程-rules参数处理(2)
    .18-浅析webpack源码之compile流程-rules参数处理(1)
    .17-浅析webpack源码之compile流程-入口函数run
    .16-浅析webpack源码之编译后流程梳理
    .15-浅析webpack源码之WebpackOptionsApply模块-plugin事件流总览
    .14-浅析webpack源码之Watchpack模块
    .13-浅析webpack源码之WatcherManager模块
    .12-浅析webpack源码之NodeWatchFileSystem模块总览
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/5840219.html
Copyright © 2011-2022 走看看