2021牛客暑期多校训练营2 K(树状数组、构造)

Stack

https://ac.nowcoder.com/acm/contest/11253/K

Description

有一个排列 , 令 表示 中满足 的个数,现在给出 个不重复的 ,问能否构造一个 排列 符合条件。

Solution

(这个做法感觉比拓扑排序好理解)
显然对于每一个 ,必须满足 ,那么对于未给出数值的 ,可以考虑先给它们填充上数值,不妨令 ,这样构造能够满足的条件,随后只需要从后往前构造即可。
从后往前构造时,假如当前 ,那么最理想的情况下是 ,但是可能在前面的构造里已经填充了 等值,所以需要用一个树状数组维护前面已经用的值,再二分找到符合条件的最小数值填到当前位置。例如 ,前面已经用了 ,那么 ,构造出来的样子就是

Code

#include<bits/stdc++.h>

const int mod = 1e9 + 7;
const int N = 1e6 + 5;

int a[N], b[N];
bool vis[N];
int T[N];

class Bit {
    public:
    int lowbit(int x) {
        return x & (-x);
    }
    Bit() {
        memset(T, 0, sizeof(T));
    }
    void update(int x, int add) {
        while (x < N) {
            T[x] += add;
            x += lowbit(x);
        }
    }
    int query(int x) {
        int res = 0;
        while (x) {
            res += T[x];
            x -= lowbit(x);
        }
        return res;
    }
};

void solve() {
    int n, k, ok = 1; std::cin >> n >> k;
    for (int i = 1; i <= k; i++) {
        int id, x; std::cin >> id >> x;
        b[id] = x;
        if (b[id] > id) {
            ok = 0;
        }
    }
    if (!ok) {
        std::cout << -1 << '\n'; return ;
    }
    Bit Tree;
    for (int i = 1; i <= n; i++) {
        Tree.update(i, 1);
    }
    for (int i = 1; i <= n; i++) {
        if (!b[i]) {
            b[i] = b[i - 1] + 1;
        }
        if (b[i] - b[i - 1] > 1) {
            std::cout << -1 << '\n'; return ;
        }
    }
    for (int i = n; i >= 1; i--) {
        int left = 1, right = n;
        int ans = -1;
        while (left <= right) {
            int mid = (left + right) >> 1;
            if (Tree.query(mid) >= b[i]) {
                ans = mid; 
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        a[i] = ans;
        Tree.update(ans, -1);
    }
    for (int i = 1; i <= n; i++) {
        std::cout << a[i] << " \n"[i == n];
    }
}

signed main() {
    std::cin.sync_with_stdio(false), std::cin.tie(nullptr);
    int T = 1; //std::cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}
全部评论
有点不理解为什么直接b[i]=b[i−1]+1,出现了b[i]比b[i-1]小不止1的时候最后该怎么构造a呢。
2 回复 分享
发布于 2021-07-20 09:43
🐂
2 回复 分享
发布于 2021-07-20 10:56
赞!
1 回复 分享
发布于 2021-07-20 00:31
终于学会这题了,谢谢大佬!
1 回复 分享
发布于 2021-07-20 13:11
做法一样!
1 回复 分享
发布于 2021-07-21 00:41
想问一下为啥要从后往前构造?想不明白
1 回复 分享
发布于 2021-07-21 22:34
TQL,谢谢dalao
点赞 回复 分享
发布于 2021-07-21 21:05
为什么大佬的代码不喜欢用 using namespace std; 呢?
点赞 回复 分享
发布于 2021-07-24 09:08
这个构造方法采取的是每次二分放当前可以放的最小值,本质上前面的数字依赖于后面数字的摆放情况,从前往后不能采取这样的二分方式,想不通为什么不可以从前往后的可以试试数据 5 2 2 1 5 4。从前往后需要用其他构造的方法,不能这样二分。
点赞 回复 分享
发布于 2021-07-24 10:04

相关推荐

醒工硬件:1学校那里把xxxxx学院去了,加了学院看着就不像本校 2简历实习和项目稍微精简一下。字太多,面试官看着累 3第一个实习格式和第二个实习不一样。建议换行 4项目描述太详细了,你快把原理图贴上来了。比如可以这样描述:使用yyyy芯片,使用xx拓扑,使用pwm控制频率与占空比,进行了了mos/电感/变压器选型,实现了xx功能 建议把技术栈和你做的较为有亮点的工作归纳出来 5熟悉正反激这个是真的吗
点赞 评论 收藏
分享
评论
12
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务