NOIP-2018 提高组(复赛) 模拟试题之--T2 最大队列

2018 noip 资料大全

问题描述
给定一个长度为的排列(共包含个整数,每个数取值范围和之间,且每个正整数出现并只出现一次)。借助一个栈,依次将这个排列的每个元素进栈,并在合适的时候出栈,可以得到不同的出栈序列。不同的操作会带来不同的出栈序列,请你求出在所有可能的方案中,字典序最大的出栈序列。
输入格式
输入数据共包括两行。
第一行包含一个正整数,表示给定的排列的长度。
第二行包含个正整数,描述给定的序列。
输出格式
仅一行,共个整数,表示你计算出的出栈序列。
样例

样例输入1

4 4 2 1 3

样例输出1

4 3 1 2

样例输入2

10 4 5 1 2 6 10 7 8 3 9

样例输出2

10 9 3 8 7 6 2 1 5 4

数据范围

所有测试点的数据规模与约定如上

题解
先说说自己的错误思路。先将所有数据排序,然后为了让字典序尽量大则每次选取当前没有被选取的最大值。同时我们维护一个上一次选取的数的位置,若的值比当前我们要出栈的元素的位置的值要小我们则直接让当前元素出栈,否则我们从将到当前位置的所有元素全部出栈。在一定程度上这样的思路是正确的,但是我们如果这样做就考虑漏了一种情况,即当我们先输出元素比我们从输出到时中间值的字典序要小,则整体字典序会比正确答案偏小。
上40分代码
#include<bits/stdc++.h>
#define maxn 200005
using namespace std;
inline int read(){
register char c=get();register int f=1,=0;
while(c>‘9’ || c<‘0’)f=(c==’-’)?-1:1,c=get();
while(c<=‘9’ && c>=‘0’)
=(<<3)+(<<1)+(c^48),c=get();
return _*f;
}
int n;
int a[maxn];
struct edge{
int a;
int flag;
}E[maxn];
bool cmp(edge a,edge b){
if(a.a!=b.a)return a.a>b.a;
return a.flag<b.flag;
}
set save;
int lastp=-1;
int out[maxn],note=1;
//map<int,int> jump;
int main(){
freopen(“seq.in”,“r”,stdin);
freopen(“seq.out”,“w”,stdout);
n=read();
//cout<<n<<endl;
for(register int i=1;i<=n;i++){
a[i]=read();
//cout<<a[i]<<" “;
E[i].a=a[i];
E[i].flag=i;
}
sort(E+1,E+1+n,cmp);
for(register int i=1;i<=n;i++){
if(save.count(E[i].a))continue;
if(lastp<E[i].flag){
out[note]=E[i].a;
save.insert(E[i].a);
note++;
lastp=E[i].flag;
}
else{
for(register int j=lastp-1;j>=E[i].flag;j–){
if(save.count(a[j]))continue;
out[note]=a[j];
note++;
save.insert(a[j]);
//jump[j]=max(jump[j],lastp-1);
}
lastp=E[i].flag;
}
}
for(register int i=1;i<note;i++){
printf(”%d",out[i]);
if(i!=note-1)printf(" ");
}
return 0;
}

事实上,为了将上述情况纳入考虑范围内,我们选择使用在线的算法。我们令当前栈顶的元素为,并使所有还没有入栈的元素中的最大值。当时我们不断入栈,直到情况不满足为止。此时则将y直接扔出去即可。当没有比栈顶元素更大的值时我们就不再入栈,而一直弹出栈顶元素直到满足条件或没有元素位置。由于每次查询最大值时的复杂度为,遍历一次的复杂度为,总复杂度则为。
朴素代码如下
#include<bits/stdc++.h>
#define maxn 200005
using namespace std;
inline char get(){
static char buf[30],*p1=buf,*p2=buf;
return p1p2 && (p2=(p1=buf)+fread(buf,1,30,stdin),p1p2)?EOF:*p1++;
}
inline int read(){
register char c=get();register int f=1,=0;
while(c>‘9’ || c<‘0’)f=(c==’-’)?-1:1,c=get();
while(c<=‘9’ && c>=‘0’)
=(<<3)+(<<1)+(c^48),c=get();
return _*f;
}
int n;
int a[maxn];
int maxnow;
int getmax(int now){
int cas=-1;
for(register int i=now;i<=n;i++)cas=max(cas,a[i]);
return cas;
}
stack box;
int out[maxn],note=1;
int main(){
//freopen(“1.txt”,“r”,stdin);
n=read();
for(register int i=1;i<=n;i++)a[i]=read();
for(register int i=1;i<=n;i++){
//cout<<box.top()<<endl;
if(box.empty()){
box.push(a[i]);
continue;
}
maxnow=getmax(i);
if(box.top()>=maxnow){
out[note]=box.top();
//cout<<out[note]<<" “;
box.pop();
note++;
i–;
continue;
}
box.push(a[i]);
}
while(!box.empty()){
out[note]=box.top();
//cout<<out[note]<<” “;
box.pop();
note++;
}
//cout<<endl;
for(register int i=1;i<note;i++)printf(”%d ",out[i]);
return 0;
}

当然朴素算法并不能满足等大数据的要求,因此我们要对算法进行优化。事实上我们可以减少取最大值的次数——我们只在开始时和每一次最大值被pop出栈时才重新取一次最大值
for(register int i=1;i<=n;i++)a[i]=read(),maxnow=max(maxnow,a[i]);
for(register int i=1;i<=n;i++){
if(i==1){
box.push(a[i]);
continue;
}
if(box.top()>=maxnow){
maxnow=getmax(i);
out[note]=box.top();
box.pop();
note++;
i–;
continue;
}
box.push(a[i]);
}

完整代码
#include<bits/stdc++.h>
#define maxn 200005
using namespace std;
inline char get(){
static char buf[30],*p1=buf,*p2=buf;
return p1p2 && (p2=(p1=buf)+fread(buf,1,30,stdin),p1p2)?EOF:*p1++;
}
inline int read(){
register char c=get();register int f=1,=0;
while(c>‘9’ || c<‘0’)f=(c==’-’)?-1:1,c=get();
while(c<=‘9’ && c>=‘0’)
=(<<3)+(<<1)+(c^48),c=get();
return _*f;
}
int n;
int a[maxn];
int maxnow;
int getmax(int now){
int cas=-1;
for(register int i=now;i<=n;i++)cas=max(cas,a[i]);
return cas;
}
stack box;
int out[maxn],note=1;
int main(){
//freopen(“1.txt”,“r”,stdin);
n=read();
for(register int i=1;i<=n;i++)a[i]=read(),maxnow=max(maxnow,a[i]);
for(register int i=1;i<=n;i++){
if(box.empty()){
box.push(a[i]);
continue;
}
if(box.top()>=maxnow){
maxnow=getmax(i);
out[note]=box.top();
//cout<<box.top()<<endl;
box.pop();
note++;
i–;
continue;
}
box.push(a[i]);
}
while(!box.empty()){
out[note]=box.top();
box.pop();
note++;
}
for(register int i=1;i<note;i++)printf("%d ",out[i]);
return 0;
}

猜你喜欢

转载自blog.csdn.net/tianli315/article/details/84869668