被去年的zyb打爆了,诶诶

与季风大战 1.5h,结果快读写挂了第一发提交爆零,怎么会是呢/ll。

为方便描述和代码实现,下文默认 \(x_i\)\(1\)\(n\) 编号,而不是从 \(0\)\(n - 1\) 编号。

题目要我们求满足条件的 \(m\) 的最小值,不妨看看它给我们的式子可以推出什么约束。

首先我们发现前两个式子把未知的 \(x_i'\)\(y_i'\) 和已知的 \(x_i\)\(y_i\) 混到一起了。这对于想要推出 \(x_i'\)\(y_i'\) 的约束的我们来说很不好。于是显然可以考虑移项,得到:

  • \(\sum\limits_{i = 1}^{m} x_i' = x - \sum\limits_{i = 1}^{m} x_{i \bmod n}\)

  • \(\sum\limits_{i = 1}^{m} y_i' = y - \sum\limits_{i = 1}^{m} y_{i \bmod n}\)

考虑第三个式子,它直接对 \(x_i'\)\(y_i'\) 进行了约束。但是我们显然不能直接构造出 \(x_i'\)\(y_i\) 并判断它们是否符合约束,于是考虑把第三个式子和前两个式子联系起来,也就是把它化成 \(\sum\limits_{i = 1}^{m} x_i'\)\(\sum\limits_{i = 1}^{m} y_i'\) 的形式。

直观感受一下,容易发现,设我们通过前两个式子得到了 \(\sum x_i'\)\(\sum y_i'\) 的取值范围,那么为了使它们也满足第三个式子,我们肯定是会把 \(x_i'\) 变得尽量平均且两两同号,对于 \(y_i'\) 同理。

因此,容易得到,第三个式子无法被满足,当且仅当 \(|\sum\limits_{i = 1}^{m} x_i'| + |\sum\limits_{i = 1}^{m} y_i'| > mk\)。充分性显然,必要性只需要考虑将 \(i\) 较小的时候的 \(x_i' + y_i'\) 设定为 \(k\) 即可。

但是这时,前两个式子的右半部分也是可变的。这个的解决方式比较容易,考虑枚举 \(m \bmod n\) 的值并每次 \(O(1) / O(\log)\) 地处理即可。也就是说,设 \(w = m \bmod n\),则 \(w\) 确定时,我们可以把这三个式子整理为一个约束:

\[|(x - \sum\limits_{i = 1}^{w} x_i) - t \sum\limits_{i = 1}^{n} x_i| + |(y - \sum\limits_{i = 1}^{w} y_i) - t \sum\limits_{i = 1}^{n} y_i| \le n t k + w k \]

这个式子中只有 \(t\) 是不确定的,它代表 \(\left\lfloor \frac{m}{n} \right\rfloor\)

这个式子的左边有两个绝对值,根据初中数学,我们可以直接把它拆成四个式子,并求符合范围的值即可。

该做法的时间、空间复杂度均为 \(O(n)\),实测不卡常、不使用 __int128、不使用快读而使用 cin / cout 并使用 endl 也能过。代码很短,只有不到 \(1.5 \text{kb}\)

#include <bits/stdc++.h>
using namespace std;
#define int long long

const int N = 1e5 + 5, INF = 1e18;

int T, n, k, x, y, min_val, max_val;
int a[N], b[N], pre1[N], pre2[N];

int Div1(int p, int q) {
	if (p % q == 0 || (p > 0 && q < 0) || (p < 0 && q > 0)) return p / q;
	else return p / q + 1;
}

int Div2(int p, int q) {
	if (p % q == 0 || (p > 0 && q > 0) || (p < 0 && q < 0)) return p / q;
	else return p / q - 1;
}

void get(int xcur, int p, int ycur, int q, int sum, int val) {
	int tmp1 = sum - p - q, tmp2 = xcur + ycur - val;
	if (tmp1 > 0 && min_val <= INF) min_val = max(min_val, Div1(tmp2, tmp1));
	else if (tmp1 < 0) max_val = min(max_val, Div2(tmp2, tmp1));
	else if (tmp2 > 0) min_val = INF + 1;
	else return;
}

void Solve() {
	int ans = INF + 1;
	cin >> n >> k >> x >> y;
	for (int i = 1; i <= n; ++i) cin >> a[i] >> b[i];
	for (int i = 1; i <= n; ++i) pre1[i] = pre1[i - 1] + a[i], pre2[i] = pre2[i - 1] + b[i];
	for (int i = 0; i <= n; ++i) {
		max_val = INF; min_val = 0;
		get(x - pre1[i], -pre1[n], y - pre2[i], -pre2[n], n * k, i * k);
		get(x - pre1[i], -pre1[n], pre2[i] - y, pre2[n], n * k, i * k);
		get(pre1[i] - x, pre1[n], y - pre2[i], -pre2[n], n * k, i * k);
		get(pre1[i] - x, pre1[n], pre2[i] - y, pre2[n], n * k, i * k);
		if (max_val >= min_val) ans = min(ans, min_val * n + i);
	}
	if (ans == INF + 1) ans = -1;
	cout << ans << endl;
}

signed main() {
	cin >> T;
	while (T--) Solve();
	return 0;
}
posted @ 2025-02-25 10:20  zyb_txdy  阅读(23)  评论(0)    收藏  举报