• SPOJ8222 NSUBSTR


    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

    本文作者:ljh2000
    作者博客:http://www.cnblogs.com/ljh2000-jump/
    转载请注明出处,侵权必究,保留最终解释权!

    题目链接:SPOJ8222

    正解:后缀自动机

    解题报告:

      我好菜啊,现在才学SAM…

      大概的构造就是在线的增量法,看看代码还是挺好懂的,简洁明了…

      有几个基础性质:自动机上的每个点上代表的字符串集合的右端点相同,$right$集合相同。

      而且两个点的$right$集合要么是包含关系,要么就不相交。

      每个节点的控制范围就是$(maxs_{fa},maxs_u]$,这样就不用维护自身的$mins$了,比较方便。

      儿子节点的$right$集合是父状态的子集,在$parent$树上往上走相当于砍掉了一个前缀。

      根据前面的性质,$|right_{fa}|= sum {|right_u|}$,那么这道题就能做了…

      自下往上搞出每个点的$right$集合大小,用集合大小去更新$maxs$的$ans$就可以了。

      要用基数排序。

    //It is made by ljh2000
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <ctime>
    #include <vector>
    #include <queue>
    #include <map>
    #include <set>
    #include <string>
    #include <complex>
    #include <bitset>
    using namespace std;
    typedef long long LL;
    typedef long double LB;
    typedef complex<double> C;
    const double pi = acos(-1);
    const int MAXN = 500011;
    int n,last,S,cnt,a[MAXN],ch[MAXN][26],len[MAXN],fa[MAXN],ans[MAXN];
    int tong[MAXN],sa[MAXN],R[MAXN],f[MAXN];
    char s[MAXN];
    
    inline int getint(){
        int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
        if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
    }
    
    inline void add(int x){
    	int c=a[x]; int p=last,np=++cnt; last=np;
    	len[np]=x; for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
    	if(!p) fa[np]=S;
    	else {
    		int q=ch[p][c];
    		if(len[q]==len[p]+1) fa[np]=q;
    		else {//不满足SAM上每个节点关于right集合的性质,拆成两个来分别接收
    			int nq=++cnt; len[nq]=len[p]+1;
    			memcpy(ch[nq],ch[q],sizeof(ch[q]));
    			fa[nq]=fa[q];
    			fa[q]=fa[np]=nq;
    			for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;//把对应的走到q的边全改成走到nq
    		}
    	}
    }
    
    inline void work(){
    	scanf("%s",s+1); n=strlen(s+1);
    	S=last=++cnt; for(int i=1;i<=n;i++) a[i]=s[i]-'a';
    	for(int i=1;i<=n;i++) add(i);
    	for(int i=1,p=S;i<=n;i++) p=ch[p][a[i]],R[p]++;//主链上的right集合初值设为1
    	for(int i=1;i<=cnt;i++) tong[ len[i] ]++;
    	for(int i=1;i<=n;i++) tong[i]+=tong[i-1];
    	for(int i=1;i<=cnt;i++) sa[ tong[ len[i] ] -- ]=i;
    	for(int i=cnt;i>=1;i--) R[ fa[ sa[i] ] ]+=R[ sa[i] ];
    	for(int i=1;i<=cnt;i++) f[ len[i] ]=max(f[ len[i] ],R[i]);//统计每种长度子串的最大出现次数,就是用right集合去更新maxs
    	for(int i=n;i>=1;i--) f[i]=max(f[i+1],f[i]);
    	for(int i=1;i<=n;i++) printf("%d
    ",f[i]);
    }
    
    int main()
    {
        work();
        return 0;
    }
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    

      

  • 相关阅读:
    sql测试
    sql时间和日期函数
    递归算法
    冒泡排序
    Ajax
    省市区下拉框三级联动
    Repeater用法
    WIndows form Linq多表联合
    C# 递归算羊
    C# 定义一个学生的结构体,输入学生信息,学号,姓名,身高,按身高排序输出
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6582393.html
Copyright © 2020-2023  润新知