POJ 3581-Sequence(字尾陣列)
阿新 • • 發佈:2018-12-24
Sequence
(n ≤ 200000)
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 6485 | Accepted: 1429 | |
Case Time Limit: 2000MS |
Description
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.
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}Source
題目意思:
有一個數組,分割成三份,每份翻轉後,得到的最小的字典序?解題思路:
字尾陣列。先確定第一段,因為A1是最大的,所以求反轉之後字串中字典序最小的字尾。 再將剩餘部分分成兩段,計算兩個原序列並將得到的新序列反轉後的字尾陣列,從中選取字典序最小的合適的字尾。 cin超時,輸入輸出外掛WA,scanf才AC…坎坷…#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> using namespace std; typedef long long ll; #define maxn 200100 int n,k,a[maxn]; int rev[maxn],sa[maxn]; int rank[maxn*2],tmp[maxn*2]; bool compare_sa(int i,int j)//倍增法,比較rank { if(rank[i]!=rank[j]) return rank[i]<rank[j]; else { int ri=i+k<=n?rank[i+k] :-1; int rj=j+k<=n?rank[j+k] :-1; return ri<rj; } } void construct_sa(int s[],int N,int sa[])//計算s的字尾陣列 { for(int i=0; i<=N; ++i)//初始長度為1,rank為字元編碼 { sa[i]=i; rank[i]=i<N?s[i] :-1; } for(k=1; k<=N; k*=2)//倍增法求字尾陣列 { sort(sa,sa+N+1,compare_sa); tmp[sa[0]]=0; for(int i=1; i<=N; ++i) tmp[sa[i]]=tmp[sa[i-1]]+(compare_sa(sa[i-1],sa[i])?1:0); for(int i=0; i<=N; ++i) rank[i]=tmp[i]; } } int main() { ios::sync_with_stdio(false); cin>>n; for(int i=0; i<n; ++i) cin>>a[i]; //solve(); reverse_copy(a,a+n,rev);//a不變,反轉a之後存入rev陣列 construct_sa(rev,n,sa);//求字尾陣列 int p1; for(int i=0; i<n; ++i)//確定第一段的分割位置 { p1=n-sa[i]; if((p1>=1)&&n-p1>=2) break; } //cout<<"p1="<<p1<<endl; int m=n-p1; reverse_copy(a+p1,a+n,rev); reverse_copy(a+p1,a+n,rev+m); construct_sa(rev,m*2,sa); int p2; for(int i=0; i<=2*m; ++i)//確定第二段的分割位置 { p2=p1+m-sa[i]; if((p2-p1>=1)&&n-p2>=1) break; } //cout<<"p2="<<p2<<endl; reverse(a,a+p1); reverse(a+p1,a+p2); reverse(a+p2,a+n); for(int i=0; i<n; ++i) cout<<a[i]<<endl; return 0; } /** 5 10 1 2 3 4 **/