您的位置:首页 > 其它

[NOIP模拟]新排序

2017-10-17 21:57 197 查看
样例输入:

4

5

1 2 3 4 5

5

5 4 3 2 1

5

1 2 3 2 1

5

2 4 1 3 5

样例输出:

5

1 2 3 4 5

0

2

1 2

3

2 3 5

数据范围:

对于40%的数据,N≤1000;

对于70%的数据,N≤50000;

对于100%的数据,T≤5;N≤100000;

题目分析:

考试总结:考试的时候,想用队列加各种情况打标记来处理,还激动的以为是正解。但是对拍又各种过不了,苦苦思考修改,结果快考完的时候,幡然醒悟单纯的队列是无法实现的。

分析:我们可以先扫一遍将不合法的点的左右两边(各一个)的数加入一个队列(可加入的条件,预备加入的数没有被加入且不是不合法的点,实际上加入的是一段不合法序列的左右两边的数),因为当你删掉这一段后,影响的就是这两个数。于是队列里又有了一些数,再对这些数判断是否有不合法的序列,重复上面的操作(此时加入左右两边的数是指不合法的数在原序列的左右两边),直到队列里面没有不合法的数。也许你会问,这和暴力模拟有什么区别。暴力模拟,每次要检查的是除掉当前不合法数后的整个序列。而上面的方法只加入不合法序列两端的两个数,因为每个数只会入队列一次(因为要判断是否已加入且它是不是不合法的数(不合法是只要这个数不合法过,就会一直标记))所以O(n)。

附代码:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std;

const int N=1e5+10;
const int INF=0x3f3f3f3f;
int t,a
,n,cnt,tot,po,ans;
bool exist
,del
,flag;
struct node{
int pos;//位于原序列的位置
int val;//大小
}q
;

int readint()
{
char ch;int i=0,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') {ch=getchar();f=-1;}
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
return i*f;
}

int main()
{
//freopen("sort.in","r",stdin);
//freopen("sort.out","w",stdout);

t=readint();
while(t--)
{
memset(del,false,sizeof(del));
memset(exist,false,sizeof(exist));
flag=false;cnt=0;
n=readint();
for(int i=1;i<=n;i++) a[i]=readint();
a[0]=-INF;a[n+1]=INF;//方便后面的判断
for(int i=1;i<=n;i++)
if(a[i]>a[i+1]||a[i]<a[i-1])//判断是否合法
{
del[i]=true;//此数不合法标记
flag=true;//是否有不合法数标记
}
for(int i=1;i<=n;i++)
{
if(del[i]==true)
{
if(i>1&&del[i-1]==false&&exist[i-1]==false)//看左边能否加入队列
{q[++cnt].pos=i-1;q[cnt].val=a[i-1];exist[i-1]=true;}
if(i<n&&del[i+1]==false&&exist[i+1]==false)//看右边能否加入队列
{q[++cnt].pos=i+1;q[cnt].val=a[i+1];exist[i+1]=true;}
}
}
while(flag==true)//循环执行
{
q[0].val=-INF;q[cnt+1].val=INF;
flag=false;tot=0;
for(int i=1;i<=cnt;i++)//判队列断是否有不和法的数
{
if(q[i].val>q[i+1].val||q[i].val<q[i-1].val)
{del[q[i].pos]=true;flag=true;exist[q[i].pos]=false;}
}
for(int i=1;i<=cnt;i++)
{
po=q[i].pos;
if(del[po])//与上面同理
{
if(po>1&&del[po-1]==false&&exist[po-1]==fal
a625
se)
{q[++tot].pos=po-1;q[tot].val=a[po-1];exist[po-1]=true;}
if(po<n&&del[po+1]==false&&exist[po+1]==false)
{q[++tot].pos=po+1;q[tot].val=a[po+1];exist[po+1]=true;}
}
else q[++tot]=q[i];//合法的依旧加入队列
}
cnt=tot;
}
ans=0;
for(int i=1;i<=n;i++) if(del[i]==false) ans++;
printf("%d\n",ans);
for(int i=1;i<=n;i++) if(del[i]==false) cout<<a[i]<<" ";//printf("%d ",a[i]);
printf("\n");
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: