AtCoder abc219_f Cleaning Robot 题解

题目传送门:AtCoderluogu
也许更好的阅读体验

思路

设集合 \(V_i\) 表示第 \(i\) 次执行时经过的点的集合。
则答案即为这 \(k\) 次操作产生的集合的并集的大小(元素个数)。
每个集合的大小均为 \(|S|\) ,需处理每次操作后重复的部分。

假设第一次执行程序后(即运行一次字符串)后扫地机器人位于 \((a, b)\)
之后的第 \(2, 3, \cdots , k\) 次后扫地机器人位于 \((2a, 2b), (3a, 3b), \cdots , (ka, kb)\)
它们恰好都在一条斜线上。由此启发,每一次执行后对应的点应该在同一斜线上。

因为每一次执行后对应的点应该在同一斜线上,所以如有重合,那么一定是位于同一斜线上的。
同样假设第一次执行程序后扫地机器人位于 \((a, b)\) ,则每次操作后对应点的偏移量就是 \((a, b)\)

设一个种类为在同一条斜线上,且可以通过移动互相到达的点。
容易发现,设 \((m, n)\) 为该种类的点的坐标,则 \((m \bmod a, n - \left \lfloor \dfrac{m}{a} \right \rfloor \times b)\) 对于所有该种类的点相同,因为 \((m \bmod a, n - \left \lfloor \dfrac{m}{a} \right \rfloor \times b)\) 为该种类第一个出现的点。

设一个点 \((x,y)\) ,将它存在对应的种类( \(S\) )之中,每次存它从第一次的位置要经过几次偏移到达现在的位置(为权值),即为 \(\left\lfloor\dfrac{m}{a}\right\rfloor\)
将种类内的点按权排序,那么答案即为两次之间的间隔之和( \(\sum_{i = 2}^n(S_i - S_{i - 1})\) ),再加上最后一点的 \(k\) 次偏移。

细节

  1. 如果第一次偏移后机器人位于 \((0, 0)\) ,那么答案即为第一次偏移机器人经过的点的个数。
  2. 若偏移后的 \(a = 0\)\(\left\lfloor\dfrac{m}{a}\right\rfloor\) 不好处理,可以将整张图的横纵坐标对换。
  3. 如果 \(a \lt 0\) ,同样不好处理,把整张图的横轴正负对换一下。
  4. 注意对负数取模。

代码

点击查看代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
typedef long long LL;

using namespace std;

const int N = 2e5 + 5;

#define FI first
#define SE second
#define PB push_back
#define PII pair<LL, LL>
#define LF(i, __l, __r) for (int i = __l; i <= __r; i++)
#define RF(i, __r, __l) for (int i = __r; i >= __l; i--)

LL k, ans;
char s[N];
LL len, nx, ny, id;
map< PII, LL> mp;
vector< PII > p;
vector<LL> vec[N];

int main() {
    scanf("%s%lld", s, &k);
    len = strlen(s);
    mp[{0, 0}] = 1;
    p.PB({0, 0});

    LF(i, 0, len - 1) {
        if (s[i] == 'L') nx -= 1;
        if (s[i] == 'R') nx += 1;
        if (s[i] == 'U') ny -= 1;
        if (s[i] == 'D') ny += 1;
        mp[{nx, ny}] = 1;
        p.PB({nx, ny});
    }

    if (nx == 0 && ny == 0) {
        printf("%d", mp.size());
        return 0;
    }

    if (nx == 0) {
        swap(nx, ny);
        LF(i, 0, p.size() - 1) swap(p[i].FI, p[i].SE);
    }

    if (nx < 0) {
        nx = -nx;
        LF(i, 0, p.size() - 1) p[i].FI = -p[i].FI;
    }

    mp.clear();

    for (auto to : p) {
        LL x = (to.FI % nx + nx) % nx, y = to.SE - ny * ((to.FI - x) / nx);
        if (!mp[{x, y}]) mp[{x, y}] = ++id;
        vec[mp[{x, y}]].PB((to.FI - x) / nx);
    }

    LF(i, 1, id) {
        sort(vec[i].begin(), vec[i].end());
        LF(j, 1, vec[i].size() - 1) ans += min(k, vec[i][j] - vec[i][j - 1]);
        ans += k;
    }

    printf("%lld", ans);
    return 0;
}

“日拱一卒无有尽,功不唐捐终入海。”——《法华经》

posted @ 2024-08-01 07:18  FRZ_29  阅读(5)  评论(0编辑  收藏  举报