原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=6215
题目大意:给出一个序列,一种操作: 对于当前数列中所有满足a[ i ]>a [ i+1 ] ( i<n)的i,同时删去所有的a[i]和a[i+1]。
操作执行到无法执行时停止,求最终的序列。
这题有个显然的性质:每个元素最多被删除一次。
利用这个性质,如果建立一个队列,队列内存所有a [ x ] - a[ pre[x] ]<0的 x和pre[x] 值,然后把这些x,pre[x]标记为即将被删去,一起删去,然后利用链表结构来维护删除后现存的前后关系,再把新产生的a [ x ] - a[ pre[x] ]<0的 x和pre[x] 值加入队列, 一直重复操作直到队列为空时停止。
因为加入队列的值一定会被删去,而一个值最多被重复删去2次,所以时间复杂度是O(n)的。
代码:
#include <bits/stdc++.h>
using namespace std;
inline void read(int &x){
char ch;
bool flag=false;
for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
x=flag?-x:x;
}
inline void read(long long &x){
char ch;
bool flag=false;
for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
x=flag?-x:x;
}
const int MAXN = 120000;
struct zy{
int st,ed;
zy( int st,int ed):st(st),ed(ed){}
zy(){}
};
vector< zy > Q;
int n;
int a[ MAXN ];
bool vis[ MAXN ];
bool use[ MAXN ];
int pre[ MAXN ];
int nex[ MAXN ];
int ans[ MAXN ];
vector< pair<int , int > > T;
void Delete(int x){
int a=pre[x];
int b=nex[x];
pre[ b ]= a;
nex[ a ]= b;
}
void doit(){
read(n);
for (int i=1;i<=n;i++)
read(a[i]);
memset( vis , 0 ,sizeof( vis ));
vis[0]=1; vis[n+1]=1;
for (int i=1;i<=n;i++)
{
pre[i]=i-1;
nex[i]=i+1;
}
Q.clear();
for (int i=2;i<=n;i++)
if ( a[i]-a[i-1] <0 )
Q.push_back( zy( i-1 ,i ) );
while ( !Q.empty() )
{
while ( !Q.empty() )
{
zy tmp;
tmp = Q.back();
Q.pop_back();
int x2=tmp.st;
int x3=tmp.ed;
T.push_back( make_pair(x2,x3 ) );
}
if (T.empty() )
break;
for (auto S:T)
{
int x=S.first;
int y=S.second;
if (!vis[x])
Delete(x);
if (!vis[y])
Delete(y);
vis[ x ] = 1; vis[ y ] = 1;
}
for (auto S:T)
{
int x=S.first;
int y=S.second;
int t1=pre[x];
int t2=nex[t1];
if ( ( ( !vis[ t1 ] ) && ( !vis[ t2 ] ) ) && ( a[t2]-a[t1]<0) )
Q.push_back( zy ( t1 , t2 ) );
}
T.clear();
}
int cnt=0;
for (int i=1;i<=n;i++)
if ( vis[ i ]==0)
ans[++cnt]=a[i];
printf("%d\n",cnt);
for (int i=1;i<=cnt;i++)
printf("%d ",ans[i]);
puts("");
}
int main(){
int T;
read(T);
for (int i=1;i<=T;i++)
doit();
return 0;
}