(后缀数组)poj 3581 Sequence
Posted 惜取少年时
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(后缀数组)poj 3581 Sequence相关的知识,希望对你有一定的参考价值。
Given a sequence, {A1, A2, ..., An} which is guaranteed A1 > 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 such i ( 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
这个题目的描述实在是太不详细,既没给范围、数据类型,也没有对“分成三部分”给出明确的定义。
在此根据自己因为题意不明出过的错误,阐明一下:
1、数据全是不超过int范围的非负数
2、“分成三部分”每一部分都不为空
希望后来做这个题目的同学如果看到这篇文章能不再因以上原因浪费不该浪费的时间。
首先将整个数组反过来看,由于第一个数是最大的,翻转之后只需要先找到此刻最小的后缀位置,就是第一个划分的区间。该位置需满足除该区间以外至少还剩余2个数。
之后再划分余下的部分。
注意到,如果一个圆环形式为[x,y][z,q] 将其两部分分别颠倒,得到[y,x] [q,z],通过整体翻转就又可以得到[x,y][z,q]的某一旋转形式。对于这样将一个大区间划分成两个小的之后再分别翻转,也是同理的。所以,可以把余下的部分再复制一份到后面(此时第一部分的已经去掉)。进行后缀数组的计算,找在非复制得到的位置的最小的后缀(且要保证余下至少1个数),就完成了对余下区间的划分。
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <queue> 8 #include <set> 9 #include <map> 10 #include <list> 11 #include <vector> 12 #include <stack> 13 #define mp make_pair 14 #define MIN(a,b) (a>b?b:a) 15 #define rank rankk 16 //#define MAX(a,b) (a>b?a:b) 17 typedef long long ll; 18 typedef unsigned long long ull; 19 const int MAX=4e5+5; 20 const int INF=2147483647; 21 const int B=1024;//桶的大小 22 const double M=4e18; 23 using namespace std; 24 const int MOD=1e9+7; 25 typedef pair<int,int> pii; 26 27 int n,k; 28 int a[MAX],rank[MAX],tmp[MAX],sa[MAX]; 29 bool cmp(int i,int j) 30 { 31 if(rank[i]!=rank[j]) 32 return rank[i]<rank[j]; 33 else 34 { 35 int ri=i+k<=n?rank[i+k]:-1; 36 int rj=j+k<=n?rank[j+k]:-1; 37 return ri<rj; 38 } 39 } 40 void construct_sa(int n) 41 { 42 if(n<=0) 43 return; 44 for(int i=1;i<=n;i++) 45 { 46 sa[i]=i; 47 rank[i]=a[i]; 48 } 49 for(k=1;k<=n;k*=2) 50 { 51 sort(sa+1,sa+n+1,cmp); 52 tmp[sa[1]]=1; 53 for(int i=2;i<=n;i++) 54 { 55 tmp[sa[i]]=tmp[sa[i-1]]+(cmp(sa[i-1],sa[i])?1:0); 56 } 57 for(int i=1;i<=n;i++) 58 rank[i]=tmp[i]; 59 } 60 } 61 int main() 62 { 63 scanf("%d",&n); 64 for(int i=1;i<=n;i++) 65 scanf("%d",&a[i]); 66 reverse(a+1,a+1+n); 67 construct_sa(n); 68 int an=INF,lo=1; 69 int p1; 70 for(int i=1;i<=n;i++) 71 { 72 if(sa[i]<=n-1&&sa[i]>=3) 73 { 74 lo=sa[i]; 75 break; 76 } 77 } 78 for(int i=lo;i<=n;i++) 79 printf("%d\n",a[i]); 80 for(int i=1;i<lo;i++) 81 a[lo+i-1]=a[i]; 82 construct_sa(2*lo-2); 83 an=INF;int los=1; 84 for(int i=1;i<=2*lo-2;i++) 85 { 86 if(lo-1-sa[i]>=0&&sa[i]>=2) 87 { 88 los=sa[i];break; 89 } 90 } 91 for(int i=los;i<lo;i++) 92 printf("%d\n",a[i]); 93 for(int i=1;i<los;i++) 94 printf("%d\n",a[i]); 95 }
以上是关于(后缀数组)poj 3581 Sequence的主要内容,如果未能解决你的问题,请参考以下文章