BZOJ 2251 [2010Beijing Wc]外星联络

时间:2022-05-08
本文章向大家介绍BZOJ 2251 [2010Beijing Wc]外星联络,主要内容包括Description、Input、Output、Sample Input、Sample Output、HINT、Source、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

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 

Source

做这道题之前我们需要首先明白一件事情

所有后缀的前缀是字符串的子串

这样我们就把子串的出现资次数转换成了求后缀的前缀的出现次数的问题

在后缀的前缀上搞事情,这会让你想到什么?

没错!后缀数组的Height数组

我们可以在Height数组里面枚举

字典序的话好处理,Height数组就是按字典序排的

首先枚举排名,在Height数组中不断枚举前缀,对于每一个前缀,不断往后枚举Height,枚举的时候统计次数。

哎呀说的好乱,自己看代码把

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int MAXN=2*1e6+10;
int sa[MAXN],rak[MAXN],tp[MAXN],tax[MAXN],a[MAXN],N,M,height[MAXN];
char s[MAXN];
void Qsort()
{
    for(int i=1;i<=M;i++) tax[i]=0;
    for(int i=1;i<=N;i++) tax[rak[i]]++;
    for(int i=1;i<=M;i++) tax[i]+=tax[i-1];
    for(int i=N;i>=1;i--) sa[ tax[rak[tp[i]]]-- ] = tp[i];
}
void Ssort()
{
    M=127;
    for(int i=1;i<=N;i++) rak[i]=a[i],tp[i]=i;Qsort();
    for(int w=1,p=1; p<N ; w<<=1,M=p)
    {
        p=0;
        for(int i=N-w+1;i<=N;i++) tp[++p]=i;
        for(int i=1;i<=N;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
        Qsort();
        swap(tp,rak);
        rak[sa[1]]=1;p=1;
        for(int i=2;i<=N;i++) rak[sa[i]] = (tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
    }
    int j,k=0;
    for(int i=1;i<=N;height[rak[i++]]=k)
        for(k=k?k-1:k,j=sa[rak[i]-1];a[i+k]==a[j+k];++k );
    for(int i=0;i<=N;i++)
    {
        for(int j=height[i]+1;;j++)
        {
            int tot=1;
            for(int k=i+1;height[k]>=j;++k,++tot);
            if(tot>1) printf("%dn",tot);
            else break;
        }
    }
}
int main()
{
    #ifdef WIN32
    freopen("a.in","r",stdin);
    #else
    #endif
    int Meiyong;
    cin>>Meiyong;
    scanf("%s",s);
    N=strlen(s);
    for(int i=1;i<=N;i++) a[i]=s[i-1];
    Ssort();
    return 0;
}