AtCoder abc219_f Cleaning Robot
題目傳送門:AtCoder, luogu
也許更好的閱讀體驗
思路
設集合 \(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\) 次偏移。
細節
- 如果第一次偏移後機器人位於 \((0, 0)\) ,那麼答案即為第一次偏移機器人經過的點的個數。
- 若偏移後的 \(a = 0\) ,\(\left\lfloor\dfrac{m}{a}\right\rfloor\) 不好處理,可以將整張圖的橫縱座標對換。
- 如果 \(a \lt 0\) ,同樣不好處理,把整張圖的橫軸正負對換一下。
- 注意對負數取模。
程式碼
#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;
}
“日拱一卒無有盡,功不唐捐終入海。”——《法華經》