题解 P10217 【[省选联考 2024] 季风】
谨以此题解纪念我今年 Day1 T1 因少分讨一个 corner case 而 F 了 10 分。
Problem
省选联考 2024 Day1 T1 季风
题目大意:
给定
找到最小的非负整数
特别地,
形象理解就是初始在原点,每次可以选择一个向量
Solution
为防止混淆,以下用
显然可以把
考虑所有模
设当前考虑的时间是
我们发现只有最后一个限制将横坐标和纵坐标绑在一起了,于是考虑用一些方法分离横纵坐标变成一个一维的问题。
原限制相当于要求
具体地,我们知道
接下来我们只考虑横坐标,纵坐标的求解是一样的。
显然
因此我们只需要满足:
方便起见我们令
现在问题转化为给定
然后考虑这个东西怎么求,只需要一些小小的分讨:
首先可以钦定
首先考虑区间下界:
- 若
tl \le 0 ,则t 的下界为0 。 - 否则若
r \le 0 ,则无解。 - 否则答案为
\left\lceil\frac{tl}{r}\right\rceil 。
然后考虑区间上界:
- 若
l \le 0 :- 若
r < 0, tl \le 0 ,则t 的上界为\left\lfloor\frac{tl}{r}\right\rfloor 。 - 否则,抛开上面提到的无解情况,答案为
+\infty 。
- 若
- 否则答案为
\left\lfloor\frac{tr}{l}\right\rfloor 。
至此这题就做完了。
Code
// Think twice, code once.
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#define eputchar(c) putc(c, stderr)
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#define eputs(str) fputs(str, stderr), putc('\n', stderr)
using namespace std;
int T, n;
long long k, tx, ty;
long long x[100005], y[100005];
void rotate(long long &x, long long &y) {
long long ax = x - y, ay = x + y;
x = ax, y = ay;
return ;
}
pair<long long, long long> calc(long long l, long long r, long long tl, long long tr) {
if (tr < 0) {
l = -l, r = -r, swap(l, r);
tl = -tl, tr = -tr, swap(tl, tr);
}
pair<long long, long long> res;
if (tl <= 0) res.first = 0;
else {
if (r > 0) res.first = (tl + r - 1) / r;
else return {0, -1};
}
if (l <= 0) {
if (r < 0 && tl <= 0) res.second = -tl / -r;
else res.second = 0x3f3f3f3f3f3f3f3f;
} else res.second = tr / l;
return res;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> T;
while (T--) {
cin >> n >> k >> tx >> ty, rotate(tx, ty);
for (int i = 0; i < n; i++) cin >> x[i] >> y[i], rotate(x[i], y[i]);
for (int i = 1; i < n; i++) x[i] += x[i - 1], y[i] += y[i - 1];
long long X = x[n - 1], Y = y[n - 1];
long long ans = -1;
for (int i = 0; i < n; i++) {
long long xp = tx, yp = ty;
if (i) xp -= x[i - 1], yp -= y[i - 1];
pair<long long, long long> ix = calc(X - n * k, X + n * k, xp - i * k, xp + i * k);
pair<long long, long long> iy = calc(Y - n * k, Y + n * k, yp - i * k, yp + i * k);
pair<long long, long long> interval(max(ix.first, iy.first), min(ix.second, iy.second));
if (interval.first > interval.second) continue;
long long res = interval.first * n + i;
if (ans == -1 || res < ans) ans = res;
}
cout << ans << '\n';
}
return 0;
}