社区讨论

请求加入题解

CF1764EDoremy's Number Line参与者 1已保存回复 0

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
0 条
当前快照
1 份
快照标识符
@mhpi0g9d
此快照首次捕获于
2025/11/08 07:40
3 个月前
此快照最后确认于
2025/11/08 07:40
3 个月前
查看原帖
本蒟蒻随便搓的贪心,看了看题解似乎没有和我思路一样的,有一位大佬是逆向思路跟我一样,但贪心的思路似乎有问题,这个方法简单又易于理解,以下是ai对我写法的概括
CF1764E 题解:逆向思维与动态贪心 这道题初看之下,需要确定一个排列 p,情况非常复杂。但如果我们反过来思考,就能发现一条清晰的解题路径。 一、核心思路:逆向思考 我们的最终目标是 用 1 号颜色染上点 k。 根据规则,这有两种途径: k <= a_1:可以直接完成,输出 YES。 k > a_1:此时必须借助一个已经被染色的点 y,满足 y <= a_1 且 k <= y + b_1。 对于第二种情况,条件可以转化为 k - b_1 <= y <= a_1。这意味着,我们需要在用 1 号颜色之前,用其他任意一个颜色(2 到 n 号),先染上一个坐标不小于 k - b_1 的点。 至此,问题被巧妙地转化了: 我们能否用 2...n 号颜色,实现“染上一个值至少为 T 的点”这个任务,其中初始目标 T = k - b_1? 同时,我们也得到了两个简单的无解判断: 若 k > a_1 + b_1,那么 k - b_1 > a_1,满足条件的 y 不存在,必为 NO。 若初始时 a_1 >= k,直接满足条件,必为 YES。 二、贪心策略:动态最优选择 现在问题变成了如何用 2...n 号颜色达成目标 T。我们可以继续运用逆向思维。 为了达成“染上点 T”这个目标,我们可以选择一个 i 号颜色(i > 1),借助它来降低问题的难度。如果我们使用 i 号颜色,问题就会变成一个更简单的子问题:“染上一个值至少为 T - b_i 的点”。 那么,在什么时候我们可以用 i 号颜色来“降低难度”呢? 当我们想从 T - b_i 拓展到 T 时,我们依赖的那个点(也就是 T-b_i)必须满足 T - b_i <= a_i,即 T <= a_i + b_i。 所以,在任何一个时刻,对于当前的目标 T,所有满足 a_i + b_i >= T 的 i 号颜色,都成为了我们的“候选工具”。 面对一堆“候选工具”,我们应该用哪个呢? 为了让目标 T 下降得最快,从而让后续的子问题最简单、选择最多,我们显然应该选择那个 b_i 最大的工具。b_i 越大,T 下降得越多。 三、算法实现 基于以上分析,我们可以设计出如下算法: 预处理: 特判 k <= a_1 和 k > a_1 + b_1 的情况。然后,将 2...n 号的 (a_i, b_i) 数对存入一个数组,并按 a_i + b_i 的值从大到小排序。这一步是为了后续能快速地将满足条件的候选颜色加入选择范围。 初始化: 设定初始目标 targ = k - b_1。 创建一个以 b_i 为第一优先级的最大优先队列(大根堆),用来存放所有可用的“候选工具”。 主循环: 首先,根据初始目标 targ,将排序后数组中所有满足 a_i + b_i >= targ 的颜色 i,将其 {b_i, a_i} 加入优先队列。 当优先队列不为空时,循环执行: 取出队首元素,即 b_i 最大的那个 {B, A}。 成功判定: 如果当前目标 targ 已经可以直接被这个颜色的 a_i 满足,即 A >= targ,说明我们已经找到了方法,直接输出 YES 并结束。 降低目标: 用这个最优工具降低目标,targ = targ - B。 更新候选: 因为目标 targ 变小了,可能会有更多颜色满足 a_i + b_i >= targ 的条件。从排序好的数组中,继续将满足新 targ 的颜色加入优先队列。 失败判定: 如果循环结束(优先队列为空),仍未找到解,则输出 NO。 这个算法通过逆向思考将问题简化,并利用优先队列在每一步都做出最优的贪心选择,从而正确地解决了问题。
CPP
#include <bits/stdc++.h>
using namespace std;
#define int long long
int X, Y, Z, n, m, u, k, Q, f, w, h;
#ifdef int
const long long inf = LLONG_MAX >> 4;
#else
const int inf = 0x3f3f3f3f;
#endif
#define FASTER ios::sync_with_stdio(0), cin.tie(0), cout.tie(0), ios_base::sync_with_stdio(0);
#define vec(a, n) vector<int> a(n + 1, 0)
#define veci(a, n) vector<int> a(n + 1, inf)
#define vecvec(a, i, j, ini) vector<vector<int>> a(i + 1, vector<int>(j + 1, ini))
#define vecin(a, n)              \
    vector<int> a(n + 1);        \
    for (int i = 1; i <= n; i++) \
        cin >> a[i];
#define strcin(x) \
    string x;     \
    cin >> x;     \
    x = ' ' + x;  \
    n = x.size() - 1;
#define all(a) a.begin(), a.end()
#define all1(a) a.begin() + 1, a.end()
#define debug(x) cerr << #x << " = " << x << "\n"
#define debug2(x, y) cerr << #x << " = " << x << "  " << #y << " = " << y << "\n"
const int mod = 998244353;
const int maxn = 1e5 + 100;
void solve()
{
    cin >> n >> k;
    vec(a, n);
    vec(b, n);
    for (int i = 1; i <= n; i++)
        cin >> a[i] >> b[i];
    vector<array<int, 3>> c(n + 1);
    for (int i = 1; i <= n; i++)
        c[i] = {a[i] + b[i], a[i], b[i]};
    sort(c.begin() + 2, c.end(), greater<array<int, 3>>());
    int loc = 2;
    if (a[1] >= k)
    {
        cout << "YES" << endl;
        return;
    }
    if (b[1] + a[1] < k)
    {
        cout << "NO" << endl;
        return;
    }
    int targ = k;
    priority_queue<pair<int, int>> q;
    q.push({b[1], a[1]});
    while (q.size())
    {
        auto [B, A] = q.top();
        q.pop();
        if (A >= targ)
        {
            cout << "YES" << endl;
            return;
        }
        int newtarg = targ - B;
        for (; c[loc][0] >= newtarg && loc <= n; loc++)
        {
            q.push({c[loc][2], c[loc][1]});
        }
        targ = newtarg;
    }
    cout << "NO" << endl;
}
signed main(void)
{
    FASTER
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
}

回复

0 条回复,欢迎继续交流。

正在加载回复...