zoukankan      html  css  js  c++  java
  • BZOJ_2251_[2010Beijing Wc]外星联络_后缀数组

    BZOJ_2251_[2010Beijing Wc]外星联络_后缀数组

    Description

    小 P 在看过电影《超时空接触》(Contact)之后被深深的打动,决心致力于寻
    找外星人的事业。于是,他每天晚上都爬在屋顶上试图用自己的收音机收听外星
    人发来的信息。虽然他收听到的仅仅是一些噪声,但是他还是按照这些噪声的高
    低电平将接收到的信号改写为由 0 和 1 构成的串, 并坚信外星人的信息就隐藏在
    其中。他认为,外星人发来的信息一定会在他接受到的 01 串中重复出现,所以
    他希望找到他接受到的 01 串中所有重复出现次数大于 1 的子串。但是他收到的
    信号串实在是太长了,于是,他希望你能编一个程序来帮助他。

    Input

    输入文件的第一行是一个整数N ,代表小 P 接收到的信号串的长度。
    输入文件第二行包含一个长度为N 的 01 串,代表小 P 接收到的信号串。

    Output

    输出文件的每一行包含一个出现次数大于1 的子串所出现的次数。输出的顺
    序按对应的子串的字典序排列。

    Sample Input

    7
    1010101

    Sample Output

    3
    3
    2
    2
    4
    3
    3
    2
    2

    HINT

      对于 100%的数据,满足 0 <=  N     <=3000


    由于是可重复子串所以有一些好做。

    对整个串求出sa和height数组。

    然后从前往后枚举子串,向后扩展,直到某个height[i]小于枚举子串的长度。

    需要注意枚举的子串长度应该从height[i]+1开始枚举,因为比它短的那些子串在前面已经枚举过了。

    时间复杂度O(nlogn+答案)<=O(n^2)。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 3050
    int n,ws[N],wv[N],wa[N],wb[N],sa[N],m=3,r[N];
    int rank[N],height[N];
    char str[N];
    void build_suffix_array() {
        int i,j,p,*x=wa,*y=wb,*t;
        for(i=0;i<m;i++) ws[i]=0;
        for(i=0;i<n;i++) ws[x[i]=r[i]]++;
        for(i=1;i<m;i++) ws[i]+=ws[i-1];
        for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
        for(j=p=1;p<n;j<<=1,m=p) {
            for(p=0,i=n-j;i<n;i++) y[p++]=i;
            for(i=0;i<n;i++) if(sa[i]-j>=0) y[p++]=sa[i]-j;
            for(i=0;i<n;i++) wv[i]=x[y[i]];
            for(i=0;i<m;i++) ws[i]=0;
            for(i=0;i<n;i++) ws[wv[i]]++;
            for(i=1;i<m;i++) ws[i]+=ws[i-1];
            for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
            for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1;i<n;i++) {
                if(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]) x[sa[i]]=p-1;
                else x[sa[i]]=p++;
            }
        }
        for(i=1;i<n;i++) rank[sa[i]]=i;
        for(i=p=0;i<n-1;height[rank[i++]]=p)
            for(p?p--:0,j=sa[rank[i]-1];r[i+p]==r[j+p];p++);
    }
    int main() {
        scanf("%d",&n);
        scanf("%s",str);
        int i,j,k;
        for(i=0;i<n;i++) r[i]=str[i]-'0'+1;
        n++;
        build_suffix_array();
        for(i=1;i<=n;i++) {
            for(j=height[i]+1;sa[i]+j-1<n;j++) {
                for(k=i+1;height[k]>=j&&k<=n;k++) ;
                if(k-i>1) printf("%d
    ",k-i);
            }
        }
    }
    
  • 相关阅读:
    特征选择常用算法综述
    干货:结合Scikit-learn介绍几种常用的特征选择方法
    机器学习中,有哪些特征选择的工程方法?
    牛逼的博客地址
    Discover Feature Engineering, How to Engineer Features and How to Get Good at It
    机器学习中的Bias(偏差),Error(误差),和Variance(方差)有什么区别和联系?
    机器学习中使用「正则化来防止过拟合」到底是一个什么原理?为什么正则化项就可以防止过拟合?
    Libsvm和Liblinear的使用经验谈
    Python 由list转为dictionary
    使用 numpy.random.choice随机采样
  • 原文地址:https://www.cnblogs.com/suika/p/9203707.html
Copyright © 2011-2022 走看看