C. Hacker, pack your bags!

题目链接👈

题目描述🥰

题目思路😀

我们首先需要处理的是如何找出持续时间和为x的两个代金券的问题

而解决这个问题最好的数据结构就是哈希表,我们可以用哈希表存入持续时间是k的所有代金券,当我们需要知道持续时间为x-k的代金券是否存在的话,那就用哈希表的count函数即可

其次我们需要解决的问题是,对于一个代金券而言,我们如何从符合和为x且与之不重叠的代金券里面找到价值最小的呢?

如果我们一个一个枚举过去,那么时间复杂度会达到O(n^2),很显然不符合我们题目的要求

而如何去优化这个问题呢?

答案是可以使用前后缀最小值并配合二分来优化

我们可以先预处理每一个时长为e的前缀最小费用和后缀最小费用,这样在后续查询单一个代金券e的时候,我们就可以用二分找到x-e的代金券里面符合x-e.r<l的最小费用和x-e.l>r的最小费用,时间就优化到nlogn的时间复杂度

AC代码🧠

struct edge{
	int l;
	int r;
	int val;
};
void solve() {
    int n, x;
    cin >> n >> x;
    map<int, vector<edge>> hash;
    for (int i = 0; i < n; ++i) {
        int l, r, val;
        cin >> l >> r >> val;
        int d = r - l + 1;
        hash[d].push_back({l, r, val});
    }
    map<int, vector<pair<int,int>>> premin, sufmin;
    for (auto &[d, vec] : hash) {
        // 预处理premin:按r升序,记录前缀最小费用
        sort(vec.begin(), vec.end(), [](const edge &a, const edge &b) {
            return a.r < b.r;
        });
        vector<pair<int, int>> tmp;
        int min_cost = LLONG_MAX;
        for (auto &v : vec) {
            min_cost = min(min_cost, v.val);
            tmp.emplace_back(v.r, min_cost);
        }
        premin[d] = tmp;
        // 预处理sufmin:按l升序,记录后缀最小费用
        tmp.clear();
        min_cost = LLONG_MAX;
        for (int i = vec.size() - 1; i >= 0; --i){
            min_cost = min(min_cost, vec[i].val);
            tmp.emplace_back(vec[i].l, min_cost);
        }
        reverse(tmp.begin(), tmp.end()); 
        sufmin[d] = tmp;
    }
    int ans = LLONG_MAX;
    for (auto &[d1, vec] : hash) {
        int d2 = x - d1;
        if (d2 <= 0 || !hash.count(d2)) continue;
        for (auto &v : vec) {
            int l = v.l, r = v.r;
            // 查找d2中满足 r_j < l 的最小费用(premin按r升序)
            auto &pre = premin[d2];
            if (!pre.empty()) {
     /*
        如果用的是(l - 1, 0LL)
        当存在 r_j == l - 1 且其费用 >= 0 的代金券时,
        这些代金券的 pair(r_j, cost) 可能等于或大于 (l - 1, 0)
        此时 upper_bound 的返回位置可能提前,导致漏掉部分满足 r_j <= l - 1 的代金券。
     */
            auto it = upper_bound(pre.begin(), pre.end(), (PII){l - 1, LLONG_MAX});
                if (it != pre.begin()) {
                    --it;
                    ans = min(ans, v.val + it->second);
                }
            }
            // 查找d2中满足 l_j > r 的最小费用(sufmin按l升序)
            auto &suf = sufmin[d2];
            if (!suf.empty()){
                auto it = lower_bound(suf.begin(), suf.end(), (PII){r + 1, 0LL});
                if (it != suf.end()) {
                    ans = min(ans, v.val + it->second);
                }
            }
        }
    }
    cout << (ans != LLONG_MAX ? ans : -1) << endl;
}

 

 posted on 2025-04-18 00:03  熙玺  阅读(22)  评论(0)    收藏  举报

Shu-How Zの小窝

Loading...