2025/7/30 模拟赛总结
\(100+20+0+46=166\),怎么成 D 题翻盘了
考虑 dp。令 \(dp_{i,j}\) 为考虑前 \(i\) 个建筑,最低的高度为 \(j\) 的最大得分。对 \(c\) 的每一行和 \(d\) 做前缀和,转移时分类讨论当前建筑是否是最低的,方程为:
\[\begin{array} \\
\displaystyle dp_{i,j} = \max\{dp_{i-1,j}+\max_{k=j+1}^{m}\{c_{i,k}\},c_{i,j}+\max_{k=0}^{j}\{dp_{i-1,k}-d_k\}+d_j\}
\end{array}
\]
前一段代表 \(i\) 不是最小值,后一段则代表当前是最低的建筑了。第一部分的 \(\max\) 可以通过 ST 表优化,后一段的 \(\max\) 可以在递推时预处理
// BLuemoon_
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int kMaxN = 1e3 + 5, kL = 12;
LL T, n, m, d[kMaxN], c[kMaxN][kMaxN], st[kMaxN][kMaxN][kL], dp[kMaxN][kMaxN], ans = -1e18, s[kMaxN];
LL query(int i, int l, int r, LL x = 0) { return l > r ? -1e18 : x = log2(r - l + 1), max(st[i][l][x], st[i][r - (1 << x) + 1][x]); }
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
for (cin >> T; T; T--, ans = -1e18) {
cin >> n >> m, fill(st[0][0], st[n + 2][0], -1e18);
for (int i = 1; i <= n; i++) {
st[i][0][0] = 0;
for (int j = 1; j <= m; j++) {
cin >> c[i][j], c[i][j] += c[i][j - 1], st[i][j][0] = c[i][j];
}
for (int j = 1; j < kL; j++) {
for (int k = 1; k <= m - (1 << j) + 1; k++) {
st[i][k][j] = max(st[i][k][j - 1], st[i][k + (1 << j - 1)][j - 1]);
}
}
}
for (int i = 0; i <= m; i++) {
cin >> d[i], i && (d[i] += d[i - 1]);
}
for (int i = 0; i <= m; i++) {
dp[1][i] = d[i] + c[1][i];
}
s[m + 1] = -1e18;
for (int j = m; ~j; j--) {
s[j] = max(s[j + 1], dp[1][j] - d[j]);
}
for (int i = 2; i <= n; i++) {
for (int j = 0; j <= m; j++) {
dp[i][j] = max(dp[i - 1][j] + query(i, j + 1, m), c[i][j] + d[j] + s[j]);
}
s[m + 1] = -1e18;
for (int j = m; ~j; j--) {
s[j] = max(s[j + 1], dp[i][j] - d[j]);
}
}
for (int i = 0; i <= m; i++) {
ans = max(ans, dp[n][i]);
}
cout << ans << '\n';
}
return 0;
}
将 \(k\ge i\&j\) 转换为 \(k\&(i\& j)=k\),即 \(k\) 的二进制是 \(i\& j\) 的子集,最后从大向小枚举取 \(\max\) 即可
计算答案时需要把 \(\min\times\max\) 也算上!
// BLuemoon_
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int kMaxN = 5e5 + 5;
const LL kP = 998244353;
LL T, n, m, a[kMaxN], b[kMaxN], mna[kMaxN], mxa[kMaxN], mnb[kMaxN], mxb[kMaxN], ans[kMaxN], cnt;
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
for (cin >> T; T; T--, cnt = 0) {
for (cin >> n, m = 1; m < n; m <<= 1) {
}
fill(mna, mna + m, 1e18), fill(mnb, mnb + m, 1e18), fill(mxa, mxa + m, -1e18), fill(mxb, mxb + m, -1e18);
for (int i = 0; i < n; i++) {
cin >> a[i], mna[i] = mxa[i] = a[i];
}
for (int i = 0; i < n; i++) {
cin >> b[i], mnb[i] = mxb[i] = b[i];
}
for (int i = m - 1; ~i; i--) {
for (int j = 1; j < m; j <<= 1) {
mxa[i] = max(mxa[i], mxa[i | j]), mxb[i] = max(mxb[i], mxb[i | j]), mna[i] = min(mna[i], mna[i | j]), mnb[i] = min(mnb[i], mnb[i | j]);
}
}
ans[n] = -1e18;
for (int i = n - 1; ~i; i--) {
ans[i] = max({ans[i + 1], mxa[i] * mxb[i], mna[i] * mnb[i], mna[i] * mxb[i], mxa[i] * mnb[i]});
}
for (int i = 0; i < n; i++) {
(cnt += ans[i]) %= kP;
}
cout << ((cnt % kP) + kP) % kP << '\n';
}
return 0;
}
TBD...
TBD...

浙公网安备 33010602011771号