您的位置:首页 > 其它

POj 3581 看起来不像后缀数组的后缀数组

2016-08-04 21:44 417 查看
先离散化数据

离散化:当数据只与它们之间的相对大小有关,而与具体是多少无关时,可以进行离散化。

思路 1:输入时反转输入,因为题目要求

2:找到最小的 i 满足 sa[i] >1 把这个后缀输出

3:翻倍剩余的字符,翻倍是因为 如 2 0 1 0 1这样的串会因为长度的问题导致字典序排序失败

4:之后对翻倍的那一段数组进行一次后缀数组

5: 求出 第一个小于第一次的边界值并且不为0的下标,之后输出都到 边界位置

6:之后把剩余的前半部分输出

7: 具体看代码

#include <stdio.h>
#include <algorithm>
#include <string.h>
#define maxs 200020
using namespace std;
struct node
{
int id;
int ns;
}nd[maxs];

bool nodecmp(node a,node b)
{
if(a.ns!=b.ns)
return a.ns<b.ns;
return a.id<b.id;
}

int wa[maxs],wb[maxs],wv[maxs],ws[maxs];

int cmp(int *r,int a,int b,int l)
{
return r[a]==r[b]&&r[a+l]==r[b+l];
}

void getsa(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb;
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=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) 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(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i],sa[i-1],j)? p-1:p++;
}
}

int s[maxs],sa[maxs];

int main()
{
int n,i,j;
scanf("%d",&n);
for(i=n-1;i>=0;i--)
{
scanf("%d",&nd[i].ns);
nd[i].id=i;
}
sort(nd,nd+n,nodecmp);

for(i=0;i<n;i++)
{
if(i&&nd[i].ns==nd[i-1].ns)
s[nd[i].id]=s[nd[i-1].id];
else s[nd[i].id]=i+1;
}
s
=0;
getsa(s,sa,n+1,n+10);
//printf("******************\n");
for(i=1;i<=n&&sa[i]<2;i++);
int first=sa[i];
for(i=first;i<n;i++)
printf("%d\n",nd[s[i]-1].ns);
for(i=0;i<first;i++)
s[i+first]=s[i];
first*=2;
s[first]=0;
getsa(s,sa,first+1,n+10);

for(i=1;i<first&&(sa[i]==0||sa[i]>=first/2);i++);
int second=sa[i];
for(i=second;i<first/2;i++)
printf("%d\n",nd[s[i]-1].ns);

for(i=0;i<second;i++)
printf("%d\n",nd[s[i]-1].ns);

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