HDU 6215 链表

来源:互联网 发布:2015乘用车销量数据 编辑:程序博客网 时间:2024/05/18 13:25

题意:

题目链接: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;}
原创粉丝点击