2021牛客暑期多校训练营2-K:Stack

题目链接

题意:原有一数组A,用B在记录A的最长不递增序列,现在告诉你pi对应的b[pi]值,要求还原出一组可行的C数组,使得1-pi位置的最长不递增序列长度为b[pi]

ps:好像我的解法和主流解法不同,而且还稍微慢一些,跑了600+ms

个人解析:
将1-n放入一个单调递增队列q里,暂时假设所有位置都是无穷大,将pi从大到小排序。
不存在的情况:i<k时,存在b[pi]-b[p(i-1)]>pi-p(i-1)时则答案不存在,因为pi-p(i-1)最多只能放下pi-p(i-1)个元素
①当pi-b[pi]+1到pi都没有重新填入数字时,我们将q的前b[pi]个元素一次填入pi-b[pi]+1到pi处,可以保证1-pi的最长不递增序列长度为b[pi]:pi-b[pi]+1之前的数都是无穷大,所以全部都被弹出,同时可以保证已经处理过的不会受到影响:更小的数字先填入,所以已经填入的数字都小于pi-b[pi]+1到pi的数字,所以后方的数字会把现在填的全部弹出
②当pi-b[pi]+1到pi都填入时,由于确保了b[pi]-b[p(i-1)]>pi-p(i-1),所以我们可以不用更改就满足条件,这条不理解可以自己琢磨一下,给出例子: b[2]=1,b[5]=4,b[6]=5
③当pi-b[pi]+1到pi部分填入时,由于pi从大到小处理,可知被填入的是后半部分,此时我们将被这段中重新填入过的元素回收到q里面,我们再将q的前b[pi]个元素一次填入pi-b[pi]+1到pi处,此时显然可以满足1-pi的最长不递增序列长度为b[pi],也可以保证已处理的不会受到影响:有①②可知被填入的数字是来自同一个p的处理,由于先填入的数字是较小的,我们将回收的数字再填入显然不会影响到已处理的结果,然后填入的非回收数字是大于所有已填的数字的,会被已填的数字给弹出,所以也不会影响已处理过的结果

AcCode

#include<iostream>
#include<algorithm>
#include<set>
#include<cstdio>
#include<queue>

using namespace std;

//#define int long long
//#define inf 1010000000

const int N = 1e6 + 100;

set<int> st;
int out[N];

priority_queue<int, vector<int>, greater<int> >q;

struct node {
    int index;
    int len;
    node() {};
    node(int index, int len) :index(index), len(len) {};
}arr[N];

inline bool cmp(node a, node b) {
    return a.index > b.index;
}

signed main() {
    int n, k;
    //cin >> n >> k;
    scanf("%d %d", &n, &k);
    bool ret = false;
    for (int i = 1; i <= n; i++) q.push(i);
    for (int i = 1; i <= k; i++) {
        int p, x;
        scanf("%d %d", &p, &x);
        if (x > p) ret = true;
        arr[i] = node(p, x);
    }
    if (ret) {
        printf("-1\n");
        return 0;
    }
    sort(arr + 1, arr + 1 + k, cmp);
    for (int i = 1; i < k; i++) {
        if ((arr[i].index - arr[i + 1].index) < (arr[i].len - arr[i + 1].len)) {
            printf("-1\n");
            return 0;
        }
    }
    for (int i = 1; i <= k; i++) {
        if (out[arr[i].index - arr[i].len + 1]) continue;
        for (int j = arr[i].index - arr[i].len + 1; j <= arr[i].index; j++) {
            if (out[j]) q.push(out[j]);
        }
        for (int j = arr[i].index - arr[i].len + 1; j <= arr[i].index; j++) {
            out[j] = q.top();
            q.pop();
        }
    }
    int maxm = n;
    for (int i = 1; i <= n; i++) {
        if (!out[i]) {
            out[i] = maxm--;
        }
    }
    for (int i = 1; i <= n; i++) printf("%d ", out[i]);
    printf("\n");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值