題意:
題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=6215
給出n個數的序列,每一輪需要刪除當前這一輪比左邊的數小或者比右邊的數大的數字,然後再將剩下的部分合並,進行下一輪。最後序列變成非遞減時結束,輸出最後序列。
思路:
很顯然每一輪就刪掉一段遞減的序列,比如,{1,2,3,7,6,5,8}刪除的就是7,6,5,可以發現,每次刪除一段後只會對這一段左右兩邊的數字有影響。
採用鏈表維護,每次刪除後將左右兩邊的鏈表的合併起來,爲了避免對已經正確排序的數字產生大量的重複掃描,所以在新一輪的待排序的head數組中只存放前一輪的刪除段左邊的第一個數字,比如上述例子新數組只存放3,然後每次從head數組開始掃描,找到遞減段,刪除後再次更新head數組即可。
詳見代碼。
代碼:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
int a[MAXN], nxt[MAXN], last[MAXN], head[MAXN];
int main() {
//freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while (T--) {
int n, s = 0, t = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
nxt[i] = i + 1;
last[i] = i - 1;
head[t++] = i;
}
a[0] = 0; nxt[0] = 1; last[n + 1] = n;
int ans = n, flag = 1;
while (flag) {
int x = 0, s = 0;
flag = 0;
while (x < t) {
int now = head[x], cnt = 0;
while (nxt[now] <= n && a[now] > a[nxt[now]]) {
now = nxt[now]; ++cnt; flag = 1;
}
if (cnt) {
ans -= (cnt + 1);
nxt[last[head[x]]] = nxt[now];
last[nxt[now]] = last[head[x]];
head[s++] = last[head[x]];
}
while (head[x] <= now && x < t) ++x;
}
t = s;
}
printf("%d\n", ans);
int x = 0;
while (x <= n) {
if (x != 0) printf("%d ", a[x]);
x = nxt[x];
}
printf("\n");
}
return 0;
}