Problem 2 |
切序列(cut.cpp/c/pas) |
||
题目描述 |
何老板发现了一个有趣的数列问题,他想用它来考考你。 给你一个由n个非负整数构成的数列{A1, A2, ..., An} 其中有 A1 > A2, ..., An, 也就是第一项是数列中最大的一个数。 你要做的是把这个数列切割成3段,切割后把每一段的数字都前后颠倒,然后再把这三段都连接起来,得到一个新的数列,要求这个新的数列的字典序最小。详情见样例。 |
||
输入格式 |
第一行,一个正整数N 第二行,N个空格间隔的整数,表示给出的数列。 |
||
输出格式 |
一行,N个空格间隔的整数,表示所求的数列。 |
||
输入样例 |
输入样例1 |
输入样例2 |
|
5 10 1 2 3 4 |
7 10 0 2 1 5 2 3 |
||
输出样例 |
输出样例1 |
输出样例2 |
|
1 10 2 4 3 |
0 10 1 2 3 2 5 |
||
数据范围 |
对于50%的数据: 1≤N≤100 对于100%的数据: 1≤N≤200000 数列中的数字≤10000 |
||
样例说明 |
样例1说明: {10,1,2,3,4} -> {10,1|2|3,4} -> {1,10|2|4,3}-> {1,10,2,4,3} 样例2说明: {10,0,2,1,5,2,3}->{10,0|2,1|5,2,3}->{0,10|1,2|3,2,5}->{0,10,1,2,3,2,5} |
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int a[200005],s[400005],n;
int work(int Len,int st){
int k,i=st,j=st+1;
while(i<=Len&&j<=Len){
for(k=0;k<Len;k++)
if(s[i+k]!=s[j+k])break;
if(k==Len)break;
if(s[i+k]>s[j+k])i+=k+1;
else if(s[i+k]<s[j+k])j+=k+1;
if(i==j)j++;
}
return min(i,j);
}//最小表示法
void out(int x,int y){
for(int i=x;i<=y;i++)printf("%d\n",a[i]);
}//输出函数
int main(){
int n,i,x,y;
scanf("%d",&n);
for(i=n;i>=1;i--)scanf("%d",&a[i]);
for(i=1;i<=n;i++){
s[i]=a[i];
s[i+n]=a[i];
}
x=work(n,3);
out(x,n);
for(i=1;i<x;i++){
s[i]=a[i];
s[i+x-1]=a[i];
}
y=work(x-1,2);
out(y,x-1);
out(1,y-1);
}