样例输入:
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
02
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;
}