nkoj 2513
Description
给定一个序列{A1,A2,...,An},保证A1>A2, ..., An。
你要把它分成三段,每段单独翻转后按照原来的顺序组成新的序列,使新的序列字典序最小。
Input
第一行一个正整数n。 (n ≤ 200000)
接下来n行每行一个数,第i+1行的数为所给序列的Ai。
Output
共n行,每行一个数。第i行为操作后新序列的第i个数
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} -> {1,10,2,4,3}
1<=Ai<=109
分析:
将输入的数倒序存储到s[i]中,在s[1]......s[n]上跑一次最小表示法得到cut1(起点为3,要保证切3段);
再在s[1].....s[cut1-1]上跑一次最小表示法得到cut2(起点为2);
那么要打印出来的三段就是s[cut1].....s[n] s[cut2]....s[cut1-1] s[1]......s[cut2-1];
代码如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<queue> using namespace std; const int maxn=200000+5; int n,s[maxn*2],temp[maxn*2]; int get_min(int len,int st){ //长度为len ,起点为ST; int i,j,k; i=st;j=st+1; while(i<=len&&j<=len){ for(k=0;k<len;k++) if(temp[i+k]!=temp[j+k])break; if(k==len)break; if(temp[i+k]>temp[j+k])i+=k+1; else if(temp[i+k]<temp[j+k])j+=k+1; if(i==j)j++; } return min(i,j); } void _print(int L,int R){ for(int i=L;i<=R;i++)printf("%d\n",s[i]); } int main(){ int i,cut1,cut2; scanf("%d",&n); for(i=n;i>0;i--)scanf("%d",&s[i]); //到序存 for(i=1;i<=n;i++)temp[i]=temp[i+n]=s[i]; cut1=get_min(n,3); for(i=1;i<cut1;i++)temp[i]=temp[i+cut1-1]=s[i]; cut2=get_min(cut1-1,2); cout<<cut1<<" "<<cut2<<endl; _print(cut1,n); _print(cut2,cut1-1); _print(1,cut2-1); }
详细注释版:
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; int a[400005],b[400005]; int len; int work(int pos,int len2){ //字符串的最小表示 int i,j,k; i=pos;j=pos+1; while(i<=len2&&j<=len2){ for(k=0;k<len2;k++)//注意,k不是下标,而是长度,所以 (k=0;k<len2;k++) if(b[i+k]!=b[j+k])break; if(k==len2)break; if(b[i+k]>b[j+k])i=i+k+1; else if(b[i+k]<b[j+k])j=j+k+1; if(i==j)j++; } return min(i,j); } int main(){ int n,m,i,j,k,ans,ans2,ans3; scanf("%d",&len); for(i=len;i>=1;i--){ scanf("%d",&a[i]);//题目要求每一段都要颠倒,倒序输入 } for(i=1;i<=len;i++){ b[i]=a[i]; b[i+len]=b[i];//复制一遍 } ans=work(3,len);//得到第一次切割的位置 ,要保证后面还能切,位置>=3 for(i=ans;i<=len;i++)printf("%d\n",a[i]); for(i=1;i<ans;i++){ //第二次的数组长度为1--ans-1 b[i+ans-1]=b[i]; } ans2=work(2,ans-1);//要保证后面还剩一段 ,位置>=2 for(i=ans2;i<ans;i++)printf("%d\n",a[i]); //出答案 for(i=1;i<ans2;i++)printf("%d\n",a[i]); }