2026.10.12 考试总结
考试总结
估:100 + 100 + 46 + 15
实:100 + 100 + 64 + 3 rk1
打暴力打的,天天不想正解导致的。
T1
原(但要求线性,考试时可以带 \(\log\)):Matrix Transformation
将在 \(b\) 上加转化为 \(a\) 上减,并 \(a_{i, j} \gets b_{i, j} - a_{i, j}\)。不难发现对于任意 \(i\) 有 \(\forall j a_{i, j} - a_{i - 1, j}\) 不变,原因显然,对于 \(j\) 也是一样的。选一个基准位置直接算即可。
code
#include <bits/stdc++.h>
using namespace std;
#define int ll
#define ll long long
#define usd unsigned
#define el putchar('\n')
#define lowbit(x) (x & (-x))
#define AC return
#define AK return 0
#define YS cout << "YES"
#define NO cout << "NO"
#define Ys cout << "Yes"
#define No cout << "No"
#define ys cout << "yes"
#define no cout << "no"
#define ls(i) ch[i][0]
#define rs(i) ch[i][1]
#define debug(num) cerr << #num << ' ' << num << '\n'
#define void inline void
#define il inline
#define Mod(x) (((x) % mod + mod) % mod)
#define pii pair <int, int>
#define pll pair <ll, ll>
il char gc() { char c; while((c = getchar()) <= ' ') ; return c; }
il int rd() {
char c; int x, f = 1;
while(!isdigit(c = getchar())) if(c == '-') f *= -1;
x = c ^ 48;
while(isdigit(c = getchar())) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
void ACehomoxue();
signed main() {
srand(time(0));
// freopen("matrix.in", "r", stdin);
// freopen("matrix.out", "w", stdout);
int t = 1;
t = rd();
while(t--) ACehomoxue();
AK;
}
const int mod = 998244353, maxn = 1e5 + 18;
int n, m, dx[maxn], dy[maxn], ans = 0, tx, ty;
vector < vector <int> > a;
map <int, int> sx, sy, cx, cy;
vector <pii> vv;
void ACehomoxue() {
ans = 1e18;
tx = 0, ty = 0;
sx.clear(), sy.clear(), cx.clear(), cy.clear();
n = rd(), m = rd();
a = vector < vector <int> > (n + 18, vector <int> (m + 18, 0));
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
a[i][j] = -rd();
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
a[i][j] += rd();
}
}
for(int i = 2; i <= n; i++) {
dx[i] = a[i][1] - a[i - 1][1];
for(int j = 2; j <= m; j++) if(dx[i] != a[i][j] - a[i - 1][j]) { cout << -1; el; AC; }
}
for(int j = 2; j <= m; j++) {
dy[j] = a[1][j] - a[1][j - 1];
for(int i = 2; i <= n; i++) if(dy[j] != a[i][j] - a[i][j - 1]) { cout << -1; el; AC; }
}
for(int i = 1; i <= n; i++) dx[i] += dx[i - 1], cx[dx[i]]++, sx[dx[i]] += dx[i], tx += dx[i];
for(int i = 1; i <= m; i++) dy[i] += dy[i - 1], cy[dy[i]]++, sy[dy[i]] += dy[i], ty += dy[i];
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
cx[dx[i] - a[i][j]] += 0, sx[dx[i] - a[i][j]] += 0;
cy[dy[j] - a[i][j]] += 0, sy[dy[j] - a[i][j]] += 0;
}
}
int lst = 0;
for(auto &[i, j] : sx) j += lst, lst = j;
lst = 0;
for(auto &[i, j] : sy) j += lst, lst = j;
lst = 0;
for(auto &[i, j] : cx) j += lst, lst = j;
lst = 0;
for(auto &[i, j] : cy) j += lst, lst = j;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
vv.clear();
vv.push_back({dx[i], dy[j] - a[i][j]});
vv.push_back({dx[i] - a[i][j], dy[j]});
for(pii pr : vv) {
int res = 0, x = pr.first, y = pr.second;
res += cx[x] * x - sx[x] + (tx - sx[x] - (n - cx[x]) * x);
res += cy[y] * y - sy[y] + (ty - sy[y] - (m - cy[y]) * y);
ans = min(ans, res);
}
}
}
cout << ans;
el;
}
T2
原:Medals
直接分讨即可。
T3
hanghangniubi,虽然没看懂他的做法。这篇题解细节在这里。
不难发现先地铁再公交再走路不劣,将每个地铁之间当作独立段。设 \(dp_{i, j, t}\) 表示长度为 \(i\) 的段,左边到原点距离为 \(j\),右边为 \(j + t\),其中 \(t \in [0, 1]\) 即可,那么每一段的贡献就是 \(dp_{s_{i + 1} - s_i, j, 1}\)。
先考虑 \(dp_{i, j, 0}\),考虑在不在里面放公交站显然为 \([i \le 2(x - j) + 1]\),对于在里面放,枚举最左边的一个,有:
\[dp_{i, j, 0} = \sum_{len = 1} ^ {2(X - j)} dp_{i - len, j, 1}
\]
注意区间是可以反转的,我们默认右边那个时间大于等于左边。我们在考虑一下 \(dp_{i, j, 1}\) 的转移,首先还是里面不放,注意到应为 \([i \le 2(x - j)]\)。里面如果要放,有类似的转移,枚举最左边的距离左边界的位置,有:
\[dp_{i, j, 1} = \sum_{len = 1} ^ {2(X - j)} dp_{i - len, j + 1, 0}
\]
前缀和优化可以做到 \(O(kX)\),注意开不下要滚动数组。做完了。
T4
你难道想写子序列自动机吗?

浙公网安备 33010602011771号