联合省选 2024 Day1 T1 题解
cancan123456 · · 个人记录
形式化题面:给出
首先将条件变形:
我们断言该不定方程组有解的充要条件为:
上推下:由
下推上:
取
回到原题,考虑枚举
记
时间复杂度为
写法好可以写得很快,下面是我考场上写了 70 分钟的代码:
#include <cstdio>
using namespace std;
typedef long long ll;
const int N = 100005;
ll x[N], y[N], xsum[N], ysum[N];
ll abs(ll x) {
return x < 0 ? -x : x;
}
ll min(ll a, ll b) {
return a < b ? a : b;
}
ll max(ll a, ll b) {
return a > b ? a : b;
}
void swap(ll a, ll b) {
a ^= b ^= a ^= b;
}
ll ceil_div(ll a, ll b);
ll floor_div(ll a, ll b) {
if (a >= 0) {
return a / b;
} else {
return -ceil_div(-a, b);
}
}
ll ceil_div(ll a, ll b) {
if (a >= 0) {
return (a + b - 1) / b;
} else {
return -floor_div(-a, b);
}
}
struct Solution {
ll l, r;
bool okl, okr;
Solution() {
okl = okr = false;
}
bool empty() {
return okl && okr && l > r;
}
ll get_min() {
if (empty()) {
return -1;
} else if (!okl) {
return 0;
} else if (okr && r < 0) {
return -1;
} else {
return max(l, 0);
}
}
};
Solution empty_sol() {
Solution E;
E.okl = E.okr = true;
E.l = +1;
E.r = -1;
return E;
}
Solution operator + (const Solution & a, const Solution & b) {
Solution c;
if (a.okl && b.okl) {
c.okl = true;
c.l = max(a.l, b.l);
} else if (a.okl && !b.okl) {
c.okl = true;
c.l = a.l;
} else if (!a.okl && b.okl) {
c.okl = true;
c.l = b.l;
} else {
c.okl = false;
}
if (a.okr && b.okr) {
c.okr = true;
c.r = min(a.r, b.r);
} else if (a.okr && !b.okr) {
c.okr = true;
c.r = a.r;
} else if (!a.okr && b.okr) {
c.okr = true;
c.r = b.r;
} else {
c.okr = false;
}
return c;
}
Solution solve_kx_ge_b(ll k, ll b);
Solution solve_kx_le_b(ll k, ll b) {
// solution of kx <= b
if (k == 0) {
return 0 <= b ? Solution() : empty_sol();
} else if (k > 0) {
Solution res;
res.okr = true;
res.r = floor_div(b, k);
return res;
} else {
return solve_kx_ge_b(-k, -b);
}
}
Solution solve_kx_ge_b(ll k, ll b) {
// solution of kx >= b
if (k == 0) {
return 0 >= b ? Solution() : empty_sol();
} else if (k > 0) {
Solution res;
res.okl = true;
res.l = ceil_div(b, k);
return res;
} else {
return solve_kx_le_b(-k, -b);
}
}
ll my_min(ll a, ll b) {
if (a == -1 || b == -1) {
return a + b + 1;
} else {
return min(a, b);
}
}
ll my_kP_plus_b(ll P, ll k, ll b) {
if (P == -1) {
return -1;
} else {
return k * P + b;
}
}
int main() {
freopen("wind.in", "r", stdin);
freopen("wind.out", "w", stdout);
int T;
scanf("%d", &T);
ll k, X, Y;
for (int n; T != 0; T--) {
scanf("%d %lld %lld %lld", &n, &k, &X, &Y);
for (int i = 0; i < n; i++) {
scanf("%lld %lld", &x[i], &y[i]);
}
for (int i = 1; i <= n; i++) {
xsum[i] = xsum[i - 1] + x[i - 1];
ysum[i] = ysum[i - 1] + y[i - 1];
}
ll ans = -1;
for (int i = 0; i < n; i++) {
// k mod n = i.
ll k1 = xsum[n], k2 = ysum[n];
ll b1 = xsum[i] - X, b2 = ysum[i] - Y;
// solve abs(k1 * P + b1) + abs(k2 * P + b2) <= n * k * P + i * k
ans = my_min(ans, my_kP_plus_b((solve_kx_ge_b(k1, -b1) + solve_kx_ge_b(k2, -b2) + solve_kx_le_b(+k1 + k2 - n * k, i * k - b1 - b2)).get_min(), n, i));
ans = my_min(ans, my_kP_plus_b((solve_kx_ge_b(k1, -b1) + solve_kx_le_b(k2, -b2) + solve_kx_le_b(+k1 - k2 - n * k, i * k - b1 + b2)).get_min(), n, i));
ans = my_min(ans, my_kP_plus_b((solve_kx_le_b(k1, -b1) + solve_kx_ge_b(k2, -b2) + solve_kx_le_b(-k1 + k2 - n * k, i * k + b1 - b2)).get_min(), n, i));
ans = my_min(ans, my_kP_plus_b((solve_kx_le_b(k1, -b1) + solve_kx_le_b(k2, -b2) + solve_kx_le_b(-k1 - k2 - n * k, i * k + b1 + b2)).get_min(), n, i));
}
printf("%lld\n", ans);
}
return 0;
}
代码第 45 行和第 47 行的 if 顺序写反了,对