BZOJ2251: [2010Beijing Wc]外星联络 后缀数组

2251: [2010Beijing Wc]外星联络

Time Limit: 30 Sec   Memory Limit: 256 MB
Submit: 791   Solved: 475
题解:
后缀数组的题,因为要求输出按字典序排序,而后缀数组中的height数组是满足这个条件的,我们只需要利用height数组来找出所有的LCP能向后扩展多少
具体的说一下:
height可以抽象成在水平方向有长度的量, 这样我们把后缀排列后逆时针旋转90度,就 可以把height数组看成一个有高度的东西,这样对于每一个高度只需从左向右求最多能扩展多少就可以了。

图片中红色线的长度就是我们所需要输出的答案
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=3005;
int n,m,p,wa[N],wb[N],SA[N],RK[N],HE[N],c[N],pos[N];
char s[N];
void GetSA()
{
	int *x=wa,*y=wb;
	m=255;
	for(int i=1;i<=n;i++) c[x[i]=s[i]]++;
	for(int i=1;i<=m;i++) c[i]+=c[i-1];
	for(int i=n;i>=1;i--) SA[c[x[i]]--]=i;
	for(int k=1;p<n;k<<=1)
	{
		p=0;
		for(int i=n-k+1;i<=n;i++) y[++p]=i;
		for(int i=1;i<=n;i++)
		if(SA[i]>k) y[++p]=SA[i]-k;
		memset(c,0,sizeof(c));
		for(int i=1;i<=n;i++) c[x[y[i]]]++;
		for(int i=1;i<=m;i++) c[i]+=c[i-1];
		for(int i=n;i>=1;i--) SA[c[x[y[i]]]--]=y[i];
		swap(x,y);
		p=1;
		x[SA[1]]=p;
		for(int i=2;i<=n;i++)
		{
			if(y[SA[i]]!=y[SA[i-1]]||y[SA[i]+k]!=y[SA[i-1]+k]) p++;
			x[SA[i]]=p;
		}
		m=p;
	}
}
void GetRK()
{
	for(int i=1;i<=n;i++) RK[SA[i]]=i; 
}
void GetHE()
{
	int j=0;
	for(int i=1;i<=n;i++)
	{
		if(RK[i]==1) continue;
		while(s[i+j]==s[SA[RK[i]-1]+j]) j++;
		HE[RK[i]]=j;
		if(j) j--;
	}
} 
int main()
{
	scanf("%d%s",&n,s+1);
	GetSA();
	GetRK();
	GetHE();
	int mx=0;
	for(int i=2;i<=n;i++)
	{
		if(HE[i]>HE[i-1])
		for(int j=mx+1;j<=HE[i];j++)
		{
			int k=i,now=1;
			while(HE[k]>=j) now++,k++;
			printf("%d\n",now);
		}
		mx=HE[i];
	}
}

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

[Submit][Status][Discuss]
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值