2025.8.30 模拟赛
T1
由于绝对值即使取负数对求最大值的答案也没有影响。
\[|x_i-x_j|+|y_i-y_j|= \max(x_i-x_j,x_j-x_i)+\max(y_i-y_j,y_j-y_i)
\]
\[=max(x_i-x_j+y_i-y_j,x_j-x_i+y_i-y_j,x_i-x_j+y_j-y_i,x_j-x_i+y_j-y_i)
\]
对于更高维的也就是 \(2^k\) 次方枚举符号的问题,复杂度 \(O(n2^k)\)。
赛时代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int n, k;
int x[N][4];
int p[N], q[N], ans;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> k;
for (int i = 1; i <= n; ++i)
for (int j = 0; j < k; ++j)
cin >> x[i][j];
for (int s = 0; s < (1 << k); ++s) {
p[0] = q[n + 1] = 1e9;
for (int i = 1; i <= n; ++i) {
p[i] = q[i] = 0;
for (int j = 0; j < k; ++j) {
p[i] += x[i][j] * ((s >> j & 1) ? 1 : -1);
q[i] += x[i][j] * ((s >> j & 1) ? 1 : -1);
}
p[i] = min(p[i], p[i - 1]);
}
for (int i = n; i >= 1; --i) {
q[i] = min(q[i], q[i + 1]);
int res = 0;
for (int j = 0; j < k; ++j)
res += x[i][j] * ((s >> j & 1) ? 1 : -1);
ans = max(ans, res - min(p[i - 1], q[i + 1]));
}
}
cout << ans << '\n';
return 0;
}
T2
给出一个字符串的 \(kmp\) 数组,求它的 \(Z\) 函数数组,保证有解。\(1\le n\le 10^6\)。
赛题有一点区别就是 \(Z\) 函数 \(z_1=0\) 或 \(z_1=n\) 的区别。
然后一段 \(kmp_i\) 告诉我们某两端是相等的,用并查集合并一下,求 \(z\) 的时候判断相等就是判断是否在同一集合。
然后根据 kmp 的性质,每次我们只用合并 \(i\) 与 \(kmp_i\) 这两个位置就好了。
赛时代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int n, nxt[N], fa[N], z[N];
void Max(int &x, int y) { x = max(x, y); }
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
void merge(int x, int y) {
if ((x = find(x)) != (y = find(y)))
fa[x] = y;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; ++i) {
fa[i] = i;
cin >> nxt[i];
if (nxt[i])
merge(i, nxt[i]);
}
z[1] = n;
for (int i = 2, l = 0, r = 0; i <= n; ++i) {
if (i <= r)
z[i] = min(z[i - l + 1], r - i + 1);
while (i + z[i] <= n && find(i + z[i]) == find(z[i] + 1))
++z[i];
if (i + z[i] - 1 > r)
l = i, r = i + z[i] - 1;
}
for (int i = 1; i <= n; ++i)
cout << z[i] << ' ';
return 0;
}
T3
x1
x23
x456
....
给一个 \(n\) 行的三角 \(a\) 形状如上,第 \(i\) 行有 \(i\) 个数,有 \(m\) 个限制形如 \(a_{x,y}\le z\),以及要求每一个左上角为
x的矩形的左下,右上,右下三个数 \(b_1,b_2,b_3\) 有任意 \(b_i\le b_j+b_k\)。例如编号 \(6\) 这个位置有 \(\le 1+5,\le 3+4\)。\(q\) 次询问 \(a_{x_1,y_1}+a_{x_2,y_2}\) 的最大可能值。
这玩意形似差分约束,长得又像 floyd 的过程。将这个三角形在左上方复制一遍就可以解决互相关系,然后做一遍类似 floyd 的东西。诈骗的地方在于存在方案可以最大化全局,\(q\) 次询问是假的。
赛时代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n, m, q, a[N][N];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m >> q, memset(a, 0x3f, sizeof(a));
++n;
for (int i = 1, x, y, z; i <= m; ++i) {
cin >> x >> y >> z;
y = n - x + y, ++x;
a[x][y] = a[n - y + 1][n - x + 1] = z;
}
for (int k = 1; k <= n; ++k) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
a[i][j] = min(a[i][j], a[i][k] + a[n - k + 1][j]);
}
}
}
for (int x, y, i, j; q; --q)
cin >> x >> y >> i >> j, cout << a[x + 1][n - x + y] + a[i + 1][n - i + j] << '\n';
return 0;
}

浙公网安备 33010602011771号