题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6215
题意:给你长度为n的数组,定义已经排列过的串为:相邻两项a[i],a[i+1],满足a[i]<=a[i+1]。我们每次对当前数组删除非排序过的串,合并剩下的串,继续删,直到排序完成。
解法:双向链表模拟过程,设置一个队列,用于存可能产生非排序过的串的头结点,每次从队列中拿出一个头结点判断后面的情况,若还能继续删除,则将头结点的上一个结点放入队列继续判,知道没有别的结点为止。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int a[maxn], Next[maxn], Last[maxn];
int que[maxn], top;
int main()
{
int T, n;
scanf("%d", &T);
while(T--){
scanf("%d", &n);
a[0] = 0;
Next[0] = 1;
Last[n+1] = n;
int ans = n;
for(int i=1; i<=n; i++){
Next[i] = i+1;
Last[i] = i-1;
scanf("%d", &a[i]);
que[top++] = i;
}
int flag = 1;
while(flag)
{
flag = 0;
int s = 0;
int now = 0;
while(now < top){
int item = que[now];
int len = 0;
while(Next[item]<=n){
if(a[item] > a[Next[item]]){
len++;
flag = 1;
item = Next[item];
}
else break;
}
if(len) ans = ans - len - 1;
if(len){
Next[Last[que[now]]] = Next[item];
Last[Next[item]] = Last[que[now]];
que[s++] = Last[que[now]];
}
while(now < top && que[now] <= item) now++;
}
top = s;
}
printf("%d\n", ans);
int now = 0;
while(now <= n){
if(now != 0) printf("%d ", a[now]);
now = Next[now];
}
printf("\n");
}
return 0;
}