ABC369F F - Gather Coins 题解

题目链接:https://atcoder.jp/contests/abc369/tasks/abc369_f

题目大意:

在一个 H×W 的二维迷宫中有 N 枚硬币,其中第 i 枚硬币在 (Ri,Ci)(本题中,我们用 (r,c) 表示二维迷宫中从上到下第 r 行从左到右第 c 列的那个格子)。

你一开始在迷宫的左上角 (1,1) 处,你要移动到一共的右下角 (H,W),但是你每次移动智能向右或向下移动一格。

求:路径上最多能够收集到的硬币数?同时,还要求输出任意一种满足条件的移动方案。

数据范围:

  • 2H,W2×105
  • 1Nmin(HW2,2×105)
  • (Ri,Ci) 各不相同

题解

将所有有硬币的位置 (r,c) 按升序排序。

这里我们定义 (ri,ci)<(rj,cj) 当且仅当 ri<rj 或者 ri=rj 的情况下 ci<cj

我们假设最终移动的过程中依次手机到的硬币的位置构成的序列为:(r1,c1)(r2,c2),……,(rk,ck)

很明显 c1c2ck

所以答案就是对 (ri,ci) 排序之后对 ciLIS(这里是最长飞将子序列),求 LIS 的同时记录一下路径即可。

示例程序:

https://atcoder.jp/contests/abc369/submissions/57359342

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int H, W, n, f[maxn], m, pos[maxn], pre[maxn], ans;
struct Node {
    int r, c;

    bool operator < (const Node &b) const {
        return r < b.r || r == b.r && c < b.c;
    }
} a[maxn];

int main() {
    scanf("%d%d%d", &H, &W, &n);
    for (int i = 1; i <= n; i++)
        scanf("%d%d", &a[i].r, &a[i].c);
    sort(a+1, a+n+1);
    for (int i = 1; i <= n; i++) {
        int p = upper_bound(f, f+m, a[i].c) - f;
        if (p == m) m++;
        f[p] = a[i].c;
        pos[p] = i;
        if (p)
            pre[i] = pos[p-1];
    }
    printf("%d\n", m);
    vector<Node> vec;
    vec.push_back({H, W});
    for (int i = pos[m-1]; i; i = pre[i])
        vec.push_back({a[i].r, a[i].c});
    vec.push_back({1, 1});
    assert(vec.size() == m+2);
    reverse(vec.begin(), vec.end());
    for (int i = 0; i+1 < m+2; i++) {
        int cnt_d = vec[i+1].r - vec[i].r, cnt_r = vec[i+1].c - vec[i].c;
        while (cnt_d--) putchar('D');
        while (cnt_r--) putchar('R');
    }
    return 0;
}

参考资料:https://atcoder.jp/contests/abc369/editorial/10849

posted @   quanjun  阅读(79)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示