Sequence POJ - 3581 (后缀数组)
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
{10, 1, 2, 3, 4} -> {10, 1 | 2 | 3, 4} -> {1, 10, 2, 4, 3}
题意:给一个序列,分成三段,并且将其反转,求出最小的序列
思路:
由于字典序,所以尽量让前面的小。
利用后缀数组ht数组的性质,将原串反转,求出第一个符合要求的ht下标,即我们可以求出第一个分割点的位置(要求:当前位置必须 < n-2)
然后就只剩下一个分割点了,对于这个分割点,我们不能直接继续求最小值,因为对于 8 -1 4 1 1 4 1 1 2 这样的序列,我们继续求会求出深色位置,这样是错的,因为对于后缀数组,其相等时是将短的排在前面,但是对于我们反转来说由于前部分
相等,所以后部分可能是长的更优秀
这样我们可以想到,对一个点前面的串反转,且将后面的串反转后,就相当于1 1 4 2 1 1 4,是不是发现了什么,对于每个位置反转都是如此,那么我们可以
将 串构造成4 1 1 4 1 1 2 4 1 1 4 1 1 2,这样再求一次最小位置且满足要求的即可
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cmath> 5 #include<vector> 6 #include<algorithm> 7 using namespace std; 8 9 const int maxn = 4e5+10; 10 int s[maxn]; 11 int ss[maxn]; 12 int sa[maxn],t[maxn],t2[maxn],c[maxn]; 13 14 void build_sa(int n,int m) 15 { 16 int i,*x=t,*y=t2; 17 for(i=0; i<m; i++)c[i]=0; 18 for(i=0; i<n; i++)c[x[i]=s[i]]++; 19 for(i=1; i<m; i++)c[i]+=c[i-1]; 20 for(i=n-1; i>=0; i--)sa[--c[x[i]]]=i; 21 for(int k=1; k<=n; k<<=1) 22 { 23 int p=0; 24 for(i=n-k; i<n; i++)y[p++]=i; 25 for(i=0; i<n; i++)if(sa[i] >= k)y[p++]=sa[i]-k; 26 for(i=0; i<m; i++)c[i] = 0; 27 for(i=0; i<n; i++)c[x[y[i]]]++; 28 for(i=1; i<m; i++)c[i]+=c[i-1]; 29 for(i=n-1; i>=0; i--)sa[--c[x[y[i]]]] = y[i]; 30 swap(x,y); 31 p=1,x[sa[0]]=0; 32 for(i=1; i<n; i++) 33 x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1]+k] == y[sa[i]+k]?p-1:p++; 34 if(p>=n)break; 35 m=p; 36 } 37 } 38 39 int ht[maxn],rk[maxn]; 40 41 void getHeight(int n) 42 { 43 int i,j,k=0; 44 for(i=1; i<=n; i++)rk[sa[i]] = i; 45 for(i=0; i<n; i++) 46 { 47 if(k)k--; 48 int j = sa[rk[i]-1]; 49 while(s[i+k] == s[j+k] && s[i+k] != '$')k++; 50 ht[rk[i]] = k; 51 } 52 } 53 int n; 54 vector<int>v; 55 56 int cmp(int *s,int pos1,int pos2,int len) 57 { 58 for(int i=0; i<len; i++) 59 { 60 if(s[pos1+i] < s[pos2+i])return -1; 61 if(s[pos1+i] > s[pos2+i])return 1; 62 } 63 return 0; 64 } 65 66 int main() 67 { 68 scanf("%d",&n); 69 v.clear(); 70 for(int i=0; i<n; i++)scanf("%d",&ss[i]),v.push_back(ss[i]); 71 reverse(ss,ss+n); 72 sort(v.begin(),v.end()); 73 v.erase(unique(v.begin(),v.end()),v.end()); 74 for(int i=0; i<n; i++)s[i] = lower_bound(v.begin(),v.end(),ss[i])-v.begin()+1; 75 s[n] = 0; 76 build_sa(n+1,maxn); 77 getHeight(n); 78 int pos1 = 0; 79 int pos2 = 0; 80 for(int i=1; i<=n; i++) 81 { 82 if(sa[i] > 1) 83 { 84 pos1 = sa[i]; 85 break; 86 } 87 } 88 for(int i=0; i<pos1; i++)s[pos1+i] = s[i]; 89 int fn = 2*pos1; 90 s[fn] = 0; 91 // cout << pos1 << endl; 92 build_sa(fn+1,maxn); 93 getHeight(fn); 94 for(int i=1; i<=fn; i++) 95 { 96 if(sa[i] > 0 && sa[i] < pos1) 97 { 98 pos2 = sa[i]; 99 break; 100 } 101 } 102 for(int i=pos1; i<n; i++)printf("%d\n",ss[i]); 103 for(int i=pos2; i<pos1; i++)printf("%d\n",ss[i]); 104 for(int i=0; i<pos2; i++)printf("%d\n",ss[i]); 105 } 106 107 /* 108 9 109 9 -2 8 1 1 8 1 1 1 110 111 9 112 9 -2 8 1 1 8 1 1 2 113 */