HDU 6215 鏈表

題意:

題目鏈接: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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章