您的位置:首页 > 其它

bzoj 2251(后缀数组)

2016-04-15 19:32 211 查看

2251: [2010Beijing Wc]外星联络

Time Limit: 30 Sec Memory Limit: 256 MB

Submit: 660 Solved: 388

[Submit][Status][Discuss]

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

解题思路:后缀数组然后暴力。细节有点恶心

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<iostream>

using namespace std;

int n,k;

char s[3001];

int sa[3001],rank[3001],height[3001],zan[3001],dis[3001];

inline int read()

{

char y; int x=0,f=1; y=getchar();

while (y<'0' ||y>'9') {if (y=='-') f=-1; y=getchar();}

while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}

return x*f;

}

bool cmp(int x,int y)

{

if (rank[x]<rank[y])return true;

if (rank[x]==rank[y])

{

int u1,u2;

if (x+k<=n) u1=rank[x+k];else u1=-1;

if (y+k<=n) u2=rank[y+k];else u2=-1;

return u1<u2;

}

return false;

}

void makeheight()

{

int j=0;

for (int i=1;i<=n;++i)

{

if (j)--j;

int u1=sa[rank[i]+1];

if (u1==0)continue;

while (i+j<=n && u1+j<=n && s[i+j-1]==s[u1+j-1]) ++j;

height[rank[i]]=j;

}

}

int main()

{

n=read();

scanf("%s",s);

for (int i=1;i<=n;++i)

{

sa[i]=i; rank[i]=int(s[i-1]);

}

for (k=1;k<=n;k=k*2)

{

sort(sa+1,sa+n+1,cmp);

zan[sa[1]]=1;

for (int i=2;i<=n;++i)

{

if (cmp(sa[i-1],sa[i])) zan[sa[i]]=zan[sa[i-1]]+1;else

zan[sa[i]]=zan[sa[i-1]];

}

for (int i=1;i<=n;++i)

rank[i]=zan[i];

}

makeheight();

memset(zan,0,sizeof(zan));

for (int i=1;i<=n-1;++i)

{

memset(dis,0,sizeof(dis));

memset(sa,0,sizeof(sa));

int mx=height[i]; dis[mx]=1; ++sa[mx];

for (int j=i+1;j<=n-1;++j)

{

mx=min(mx,height[j]);

++dis[mx]; ++sa[mx];

}

for (int j=n-1;j>=1;--j)

{

zan[j]+=zan[j+1];

dis[j]+=dis[j+1]-zan[j];

}

for (int j=1;j<=n;++j)

{

if (dis[j]+1>1)printf("%d\n",dis[j]+1);

zan[j]=sa[j];

}

}

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: