Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 5738 | Accepted: 1227 | |
Case Time Limit: 2000MS |
Description
Given a sequence, {A1, A2, ..., An} which is guaranteedA1 > A2, ..., An, you are to cut it into three sub-sequences and reverse them separately to form a new one which is the smallest possible sequence in alphabet order.
The alphabet order is defined as follows: for two sequence {A1,A2, ..., An} and {B1,B2, ..., Bn}, we say {A1,A2, ..., An} is smaller than {B1,B2, ..., Bn} if and only if there exists suchi ( 1 ≤ i ≤ n) so that we have Ai <Bi and Aj = Bj for each j <i.
Input
The first line contains n. (n ≤ 200000)
The following n lines contain the sequence.
Output
output n lines which is the smallest possible sequence obtained.
Sample Input
5 10 1 2 3 4
Sample Output
1 10 2 4 3
Hint
Source
题意:给定一个数列,将其分为非空的三段。然后分别将三段的数字翻转连接在一起组成新的数列。输出处理后字典序最小的结果。
思路:首先注意必须写成单Case的形式!!!while(scanf("%d",&n)!=EOF)会RE或者WA。。。
因为要翻转,所以读入时直接反着读。由于没有告诉数值的上限,所以接下来离散化。
对于第一段:第一段翻转之后必须最小,因此对翻转过的数列求sa,则排名在前面且sa[i]>1(因为另两段不能为空)的第一个i为第一段。
接下来处理后两段:显然要让第二段的开头尽可能小,但是切去第二段后剩下的部分会直接接在第二段后面,所以不能直接求sa。为保证第三段接在第二段后面时整体最小,所以需要把剩余的串复制到剩余串的后面,再求sa.注意数组要开2倍。
以下举例转自 poj3581 Sequence(后缀数组) - Damonbaby的日志 - 网易博客
刚开始的时候觉得没有必要将剩下的数字复制一片贴在剩下的数字后面,所以wa了很多次。。。
最后在discuss里面看见一组数据:
9
8 4 -1 5 0 5 0 2 3
第一步:
3 2 0 5 0 5 -1 4 8 对应输出 -1 4 8
第二步
3 2 0 5 0 5(开始的时候我并没有复制一遍) 对应输出:0 5
第三步
3 2 0 5 对应输出: 3 2 0 5
可以看见这样做是不对的。。
必须要将剩下的字符串复制一遍贴在后面,然后再来求后缀数组。。。
正解:
第一步:
3 2 0 5 0 5 -1 4 8 对应输出 -1 4 8
第二步
3 2 0 5 0 5 3 2 0 5 0 5 对应输出: 0 5 0 5;
第三步
3 2 对应输出:3 2;
Problem: 3581 User: kxh1995
Memory: 8020K Time: 2032MS
Language: C++ Result: Accepted
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<iostream>
#define min(a,b) (a>b?b:a)
#define max(a,b) (a>b?a:b)
#define INF 0xfffffff
using namespace std;
int sa[400010],Rank[400010],rank2[400010],c[400010],*x,*y,s[400010],k,temp[400010],num[400010];
void cmp(int n,int sz)
{
int i;
memset(c,0,sizeof(c));
for(i=0;i<n;i++)
c[x[y[i]]]++;
for(i=1;i<sz;i++)
c[i]+=c[i-1];
for(i=n-1;i>=0;i--)
sa[--c[x[y[i]]]]=y[i];
}
void build_sa(int *s,int n,int sz)
{
x=Rank,y=rank2;
int i,j;
for(i=0;i<n;i++)
x[i]=s[i],y[i]=i;
cmp(n,sz);
int len;
for(len=1;len<n;len<<=1)
{
int yid=0;
for(i=n-len;i<n;i++)
{
y[yid++]=i;
}
for(i=0;i<n;i++)
if(sa[i]>=len)
y[yid++]=sa[i]-len;
cmp(n,sz);
swap(x,y);
x[sa[0]]=yid=0;
for(i=1;i<n;i++)
{
if(y[sa[i-1]]==y[sa[i]]&&sa[i-1]+len<n&&sa[i]+len<n&&y[sa[i-1]+len]==y[sa[i]+len])
x[sa[i]]=yid;
else
x[sa[i]]=++yid;
}
sz=yid+1;
if(sz>=n)
break;
}
for(i=0;i<n;i++)
Rank[i]=x[i];
}
struct s
{
int val,id;
}a[200020];
int cmp(const void *a,const void *b)
{
return (*(struct s *)a).val-(*(struct s *)b).val;
}
int main()
{
int n;
scanf("%d",&n);
int i;
for(i=n-1;i>=0;i--)
{
scanf("%d",&num[i]);
a[i].val=num[i];
a[i].id=i;
}
qsort(a,n,sizeof(a[0]),cmp);
temp[0]=1;
for(i=1;i<n;i++)
{
temp[i]=(a[i].val==a[i-1].val?temp[i-1]:i+1);
}
for(i=0;i<n;i++)
{
s[a[i].id]=temp[i];
}
s[n]=0;
build_sa(s,n+1,n+5);
int minn=INF;
for(i=1;i<=n;i++)
{
if(sa[i]>1)
break;
}
int m=sa[i];
for(i=m;i<n;i++)
{
printf("%d\n",num[i]);
}
for(i=0;i<m;i++)
{
s[m+i]=s[i];
}
int nn=m*2;
s[nn]=0;
//for(i=0;i<nn;i++)
// {
// printf("****%d\n",s[i]);
// }
build_sa(s,nn+1,n+5);
for(i=1;i<=nn;i++)
{
if(sa[i]>0&&sa[i]<m)
break;
}
int j;
for(j=sa[i];j<m;j++)
{
printf("%d\n",num[j]);
}
for(j=0;j<sa[i];j++)
{
printf("%d\n",num[j]);
}
// while(1);
}