AtCoder abc219_f Cleaning Robot 題解

FRZ_29發表於2024-08-01

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;
}

“日拱一卒無有盡,功不唐捐終入海。”——《法華經》

相關文章