当前位置: 首页 > news >正文

2025 暑期 mx 集训 7.25

T1

https://www.mxoj.net/problem/P110058?contestId=67

题意

\(n\) 个点,每个点高度为 \(a_i \in [1, m]\)

你要找到一个 \(x\),使得 \(a_i = a_{i - 1} + x \ \forall i \in (1,n]\)

你可以修改一些 \(a_i\) 使他变成 \([1, m]\) 中的任意一个数。求最小操作次数。

\(n,m\leq 10^6\)

Solution

考虑这个 \(x\) 之有 \(O(\frac{m}{n})\) 种,所以我们可以考虑如何 \(O(n)\) 算在 \(x\) 确定时的答案。

容易发现 \(a_i = (i - 1)x + h\)。所以我们只需要统计相同的 \(h\) 最多有几个即可。用数组实现。STL 常数有点大。

时间复杂度 \(O(n)\)

Code

#include <bits/stdc++.h>using namespace std;const int N = 1e6 + 10, inf = 0x3f3f3f3f;int n, m, a[N], b[N];int main()
{cin.tie(0)->ios::sync_with_stdio(false);int _; cin >> _;while (_--) {cin >> n >> m;for (int i = 1; i <= n; i++) cin >> a[i];int ans = n;for (int i = 0; i <= m / max(n - 1, 1) + 5; i++) {int c = 0;for (int j = 1; j <= n; j++) {if (a[j] >= (j - 1) * i + 1 && a[j] + (n - j) * i <= m) {b[a[j] - (j - 1) * i]++;c = max(c, b[a[j] - (j - 1) * i]);}}for (int j = 1; j <= n; j++) {if (a[j] >= (j - 1) * i && a[j] + (n - j) * i <= m) {b[a[j] - (j - 1) * i] = 0;}}ans = min(ans, n - c);}cout << ans << "\n";}return 0;
}

T2

https://www.mxoj.net/problem/P110059?contestId=67

题意

给你一张无向图,每条边上有一个隔板高 \(h_i\)

每个点有一些雨水,当某个点雨水高度大于和他相连的边的隔板高度时,水会从多的地方流向少的地方。

设每个点最终的雨水量为 \(a_i\),那么 \(a_i\)\([1,H]\) 之间的整数。求有多少种 \(a\) 序列。对 \(998244353\) 取模。

\(n,m\leq 2\times 10^5,H\leq 10^9\)

Solution

首先考虑如果一个隔板非常高,那么他可能是无用的。因为太高了,根本够不到他。

然后考虑如果水漫过了一个隔板,那么这两个点的水位只可能相等了。

也就是可以把他们看作一个点。所以这就很 Kruskal。

设最高的有用的隔板高为 \(p\),那么答案肯定是由 \(< p\) 的部分 \(+ (p, H]\) 的部分拼成。

后面这部分是好算的,就是 \(H - p\)。前面这块考虑跑最小生成树的同时求出。

考虑设 \(ans_i\) 为第 \(i\) 个连通块 \(< mx_i\) 的答案,\(mx_i\) 就是这个连通块最高的隔板高度。

然后合并两个连通块的时候和最终求答案类似:

\[ans' = (ans_x + (w - mx_x)) \times (ans_y + (w - mx_y)) \]

然后更新 \(mx\) 即可。

时间复杂度 \(O(n\log n)\)

Code

#include <bits/stdc++.h>using namespace std;#define ll long longconst int N = 2e5 + 10, P = 998244353;int n, m, H, p[N];
ll mx[N], ans[N];struct node { int u, v, w; } e[N];int fifa(int x) { return p[x] == x ? x : p[x] = fifa(p[x]); }void merge(int x, int y, int w)
{x = fifa(x), y = fifa(y);if (x == y) return;p[x] = y;ans[y] = ((ans[x] + (w - mx[x])) % P * ((ans[y] + (w - mx[y]))) % P) % P;mx[y] = w;
}int main()
{cin.tie(0)->ios::sync_with_stdio(false);cin >> n >> m >> H;for (int i = 1; i <= m; i++) {int u, v, w; cin >> u >> v >> w;e[i] = { u, v, w };}for (int i = 1; i <= n; i++) ans[i] = 0, mx[i] = -1, p[i] = i;sort (e + 1, e + m + 1, [&](node x, node y) { return x.w < y.w; });for (int i = 1; i <= m; i++) {int u = e[i].u, v = e[i].v, w = e[i].w;merge(u, v, w);}cout << (ans[fifa(1)] + (H - mx[fifa(1)])) % P;return 0;
}

T3

https://www.mxoj.net/problem/P110060?contestId=67

题意

一共 \(2n\) 个点,每行 \(n\) 个共 \(2\) 行。每个点有颜色。

\((i, j)\) 表示左脚在 \(i\) 右脚在 \(j\) 上。

你一开始在 \((0, 0)\) 要走到 \((n + 1, n + 1)\)。你要保证两只脚所处的点的颜色相等。

你可以从 \((i,j)\) 选择 \((k,l),i<k,j<l\)。然后去到 \((k,l)\) 并花费 \((k - i)^2 + (l - j)^2\) 的代价。

求最小花费。

\(n\leq 3\times 10^3\)

Solution

\(O(n^4)\) 暴力转移随便做。

然后考虑钦定每次只移动一个,可以先移动一个,然后移动另一个。

\(f_{i,j,0/1}\) 表示在 \((i,j)\),现在该动哪只脚了。

转移就枚举这只脚去哪即可。\(O(n^3)\)

然后转移是这样的:

\(f_{i,j,0} = \min f_{i,k,1} + (j - k)^2\)

\(f_{i,j,1} = \min f_{k,j,0} + (i-k)^2 \ (col_{i,0} = col_{j,1})\)

直接斜率优化转移即可。(但我不会)

Code

暴力
memset(f, 0x3f, sizeof f);
f[0][0][1] = 0;
for (int i = 0; i <= n + 1; ++i) {for (int j = 0; j <= n + 1; ++j) {// 计算 f[i][j][0]:最后动右脚,前序状态是右脚在k(k < j)// 中间状态,无需颜色相等for (int k = 0; k < j; ++k)f[i][j][0] = min(f[i][j][0], f[i][k][1] + (j - k) * (j - k));// 计算 f[i][j][1]:最后动左脚,前序状态是左脚在k(k < i)// 需满足颜色匹配条件a[i] == b[j]if (a[i] == b[j])for (int k = 0; k < i; ++k) f[i][j][1] = min(f[i][j][1], f[k][j][0] + (i - k) * (i - k));}
}
cout << f[n + 1][n + 1][1];

放一份 std。
#include <bits/stdc++.h>
using namespace std;const int N = 3010;int n;
int f[N][N][2];
int a[N], b[N];
int q1[N], q2[N][N], l2[N], r2[N];int main() {freopen("stone.in", "r", stdin);freopen("stone.out", "w", stdout); scanf("%d", &n);for (int i = 0; i <= n + 1; i++) {scanf("%d", &a[i]);}for (int i = 0; i <= n + 1; i++) {scanf("%d", &b[i]);}memset(f, 10, sizeof(f));f[0][0][1] = 0;for (int i = 0; i <= n + 1; i++) {l2[i] = 1;}for (int i = 0; i <= n + 1; i++) {int l1 = 1, r1 = 0;for (int j = 0; j <= n + 1; j++) {// 优化f[i][j][0]的转移while (l1 < r1 && f[i][q1[l1 + 1]][1] + q1[l1 + 1] * q1[l1 + 1] - f[i][q1[l1]][1] - q1[l1] * q1[l1] <= 2 * j * (q1[l1 + 1] - q1[l1])) {l1++;}// 优化f[i][j][1]的转移while (l2[j] < r2[j] && f[q2[j][l2[j] + 1]][j][0] + q2[j][l2[j] + 1] * q2[j][l2[j] + 1] - f[q2[j][l2[j]]][j][0] - q2[j][l2[j]] * q2[j][l2[j]] <= 2 * i * (q2[j][l2[j] + 1] - q2[j][l2[j]])) {l2[j]++;}// 更新f[i][j][0]if (l1 <= r1) {f[i][j][0] = f[i][q1[l1]][1] + (j - q1[l1]) * (j - q1[l1]);}// 更新f[i][j][1]if (l2[j] <= r2[j] && a[i] == b[j]) {f[i][j][1] = f[q2[j][l2[j]]][j][0] + (i - q2[j][l2[j]]) * (i - q2[j][l2[j]]);}// 维护q2[j]队列if (f[i][j][0] < f[0][0][0]) {while (l2[j] < r2[j] && (f[i][j][0] + i * i - f[q2[j][r2[j] - 1]][j][0] - q2[j][r2[j] - 1] * q2[j][r2[j] - 1]) * (q2[j][r2[j]] - q2[j][r2[j] - 1]) <= (f[q2[j][r2[j]]][j][0] + q2[j][r2[j]] * q2[j][r2[j]] - f[q2[j][r2[j] - 1]][j][0] - q2[j][r2[j] - 1] * q2[j][r2[j] - 1]) * (i - q2[j][r2[j] - 1])) {r2[j]--;}q2[j][++r2[j]] = i;}// 维护q1队列if (f[i][j][1] < f[0][0][0]) {while (l1 < r1 && (f[i][j][1] + j * j - f[i][q1[r1 - 1]][1] - q1[r1 - 1] * q1[r1 - 1]) * (q1[r1] - q1[r1 - 1]) <= (f[i][q1[r1]][1] + q1[r1] * q1[r1] - f[i][q1[r1 - 1]][1] - q1[r1 - 1] * q1[r1 - 1]) * (j - q1[r1 - 1])) {r1--;}q1[++r1] = j;}}}printf("%d", f[n + 1][n + 1][1]);return 0;
}

T4

https://www.mxoj.net/problem/P110061?contestId=67

题意

\(n\) 个点,初始时第 \(i\) 个点为 \(i\)

\(m\) 种操作形如:\(x,y\) 表示把颜色为 \(x\) 的点的颜色变为 \(y\)

然后有 \(q\) 次查询,每次查询进行 \([l,r]\) 内的操作最终有多少极长连续段。

\(n,m,q \leq 5\times 10^5\)

Solution

首先考虑固定 \(l\) 移动 \(r\)

我们可以建图,直接连 \(x\to y\) 的边。但是如果有 \(1\to 2, 2 \to 1\) 就毁了。

考虑每次建立虚点 \(p\)\(p \to x, p\to y\),然后 \(p\) 的颜色和 \(y\) 一样。

这样当 \(r\) 移到最后的时候就建出来了一个森林。

考虑颜色段数量只需要知道相邻两个位置上的颜色是否一样。

对于 \(i, i + 1\) 他们首次变得一样的时刻是 \(lca\)

用数据结构维护区间加减即可。

接下来考虑移动 \(l\),这个我不会。

考虑在前面新建一个操作有什么影响。
其实只需要新建一个节点 \(p\) 作为 \(x,y\) 的父亲,然后 \(y\) 原本的父亲作为 \(p\) 的父
亲即可,可以发现只有 \(x\) 的祖先关系会更改,重构 \(x - 1, x, x + 1\) 之间的
贡献即可。

综上我们需要加叶子求 LCA 和树状数组,前者可以用倍增动态维护。

后面这部分还不会,先放个 std 吧。

Code

#include <bits/stdc++.h>
using namespace std;const int N = 2e6 + 7;inline int read() {int X = 0;bool flag = 1;char ch = getchar();while (ch < '0' || ch > '9') {if (ch == '-') flag = 0;ch = getchar();}while (ch >= '0' && ch <= '9') {X = (X << 1) + (X << 3) + ch - '0';ch = getchar();}if (flag) return X;return ~(X - 1);
}struct node {int id, l, r;
} q[N];bool cmp(node a, node b) {return a.l > b.l;
}int rot[N], dep[N];
int t, f[N][30];int LCA(int x, int y) {if (rot[x] != rot[y]) return 0;if (dep[x] < dep[y]) swap(x, y);for (int i = t; i >= 0; i--) {if (dep[f[x][i]] >= dep[y]) {x = f[x][i];}}if (x == y) return x;for (int i = t; i >= 0; i--) {if (f[x][i] != f[y][i]) {x = f[x][i];y = f[y][i];}}return f[x][0];
}int n, m, Q;
int x[N], y[N];
int tree[N];int lowbit(int x) {return x & (-x);
}void add(int x, int v) {for (int i = x; i <= m; i += lowbit(i)) {tree[i] += v;}
}int ask(int x) {int res = 0;for (int i = x; i; i -= lowbit(i)) {res = res + tree[i];}return res;
}void Extand(int i) {int p = i + n;dep[p] = dep[y[i]];dep[y[i]] = dep[x[i]] = dep[p] + 1;if (!f[y[i]][0]) {f[p][0] = p;} else {f[p][0] = f[y[i]][0];}f[y[i]][0] = f[x[i]][0] = p;for (int k = 1; k <= t; k++) {f[p][k] = f[f[p][k - 1]][k - 1];}for (int k = 1; k <= t; k++) {f[x[i]][k] = f[f[x[i]][k - 1]][k - 1];}for (int k = 1; k <= t; k++) {f[y[i]][k] = f[f[y[i]][k - 1]][k - 1];}rot[x[i]] = rot[y[i]];
}int ans[N];int main() {n = read();m = read();Q = read();t = log2(m);for (int i = 1; i <= m; i++) {x[i] = read();y[i] = read();}for (int i = 1; i <= Q; i++) {q[i].id = i;q[i].l = read();q[i].r = read();}sort(q + 1, q + Q + 1, cmp);for (int i = 1; i <= n; i++) {rot[i] = i;}int k = m + 1;add(1, n);for (int i = 1; i <= Q; i++) {while (k > q[i].l) {k--;if (x[k] == y[k]) continue;if (x[k] != 1) {int u = LCA(x[k], x[k] - 1);if (u) add(u - n, 1);}if (x[k] != n) {int u = LCA(x[k], x[k] + 1);if (u) add(u - n, 1);}Extand(k);if (x[k] != 1) {int u = LCA(x[k], x[k] - 1);if (u) add(u - n, -1);}if (x[k] != n) {int u = LCA(x[k], x[k] + 1);if (u) add(u - n, -1);}}ans[q[i].id] = ask(q[i].r);}for (int i = 1; i <= Q; i++) {printf("%d\n", ans[i]);}return 0;
}
http://www.sczhlp.com/news/11179/

相关文章:

  • 一文带你快速了解招聘管理系统
  • Vue 的 nextTick 的原理是什么?
  • ARM CPU的 intrinsics指令集 - svcmpgt_u32
  • 河南萌新联赛2025第(五)场:信息工程大学”题解
  • IP_UV_PV介绍
  • Flutter 接入 Line 登录
  • c语言之关于AT指令连接MQTT时如何区分连接失败和中途失败
  • 路由介绍
  • 2025牛客暑期多校训练营9
  • md目录测试 - zlay
  • 普通目录测试 - zlay
  • Python提取Srec或Hex文件数据
  • ArcGisPro 编程批量分析、发布和覆盖地图服务
  • 【分享】对着 WBLT 写了(WBLT 学习报告)
  • RidgeBot 5.4.5 - 基于 AI 的主动安全验证平台
  • 函数指针用法
  • Microsoft Office LTSC 2024 for Mac (Microsoft 365) 16.100 - 文档、电子表格、演示文稿和电子邮件
  • Studio 3T 2025.14 (macOS, Linux, Windows) - MongoDB 的终极 GUI、IDE 和 客户端
  • 抖音福袋扭蛋机,抖音抢福袋工具
  • Luogu P8250 交友问题 题解 [ 蓝 ] [ 根号分治 ] [ Bitset ] [ 复杂度均摊 ]
  • Cisco Catalyst 9000 Series Switches, IOS XE Release 17.18.1 ED
  • 电脑不能连续打字,光标总是自动消失解决办法
  • 集训内容总结 day14:模拟赛 Round7
  • 数据库字段排序:desc 90怎么会在827之前?
  • tcp三次握手四次挥手介绍
  • 前端依赖库源码修改神器——patch-package 使用指南
  • Linux 的开机启动顺序
  • 【CAPL】创建路由功能并测试,Graphics的使用
  • 【自学嵌入式:stm32单片机】PWM驱动LED呼吸灯
  • Apache DolphinScheduler 7 月社区月报 | 关键修复与性能优化全面推进