bzoj 2251(后缀数组)

来源:互联网 发布:淘宝如何开话费充值 编辑:程序博客网 时间:2024/04/30 01:25

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];
     }
   } 
}

0 0