[NOIP模拟]新排序

样例输入:

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],n,cnt,tot,po,ans;
bool exist[N],del[N],flag;
struct node{
    int pos;//位于原序列的位置
    int val;//大小
}q[N];

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]==false)
                        {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;
}
发布了99 篇原创文章 · 获赞 8 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qianguch/article/details/78267188