2025.2.11 CW 模拟赛
T1
算法
区间 dp
.
思路
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
int dfs(int l, int r, int x) {
if (l > r) return 1;
if (~f[l][r][x]) return f[l][r][x];
if (a[l] < x) return f[l][r][x] = dfs(l + 1, r, x);
if (a[r] < x) return f[l][r][x] = dfs(l, r - 1, x);
int mn = 1e9;
for (int i = l; i <= r; ++i)
if (a[i] >= x) mn = min(mn, a[i]);
if (mn > x) return f[l][r][x] = dfs(l, r, mn);
int ret = 0, flag = 0;
for (int i = l; i <= r; ++i) {
if (a[i] == x) flag = 1;
if (flag and a[i] >= x)
ret = (ret + 1ll * dfs(l, i, x + 1) * dfs(i + 1, r, x + 1)) % mod;
}
return f[l][r][x] = ret;
}
T3
算法
构造.
思路
先考虑什么时候一定无解. 因为 \(a_i = i\) 的点是不动点, 所以该点两侧只能在内部交换, 那么如果左半部分中有需要被交换到右半部分中的的点 (右半部分同理), 则一定无解.
现在思考如何将 1 移动到 \(a_1\). 我们一定是需要不断向左挪的, 如果移不动 (例如 \(a_{x - 1} = x\)) 我们先交换一下顺序再移动即可. 对于 \(2 \sim n\), 同理即可.
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
for (int i = 1; i <= n; ++i) {
for (int j = 2; j < n; ++j)
if (a[j] ^ j and a[j] == j + 1 and a[j - 1] ^ j - 1 and a[j - 1] ^ j) {
ans.push_back({j - 1, j});
swap(pos[a[j]], pos[a[j - 1]]);
swap(a[j], a[j - 1]);
}
for (int j = pos[i]; j > i; --j) {
ans.push_back({j - 1, j});
swap(pos[a[j]], pos[a[j - 1]]);
swap(a[j], a[j - 1]);
}
}
T4
算法
多源 bfs
, 最小生成树.
思路
题目要求使得路径中最大权值最小, 很难不想到最小生成树. 同时有一个朴素的想法: 两两房子之间分别连边, 再在图中求最小生成树. 但是 \(m \le 2 \times 10^5\), \(\mathcal{O}(n^2)\) 连边会超时, 考虑优化.
经过思考可以发现, 又很多边其实是不优的, 所以我们通过多源 bfs
, 从多个点出发进行染色, 只在颜色相撞的两点连边, 这样就可以保证边的数量不会太多, 从而保证复杂度正确.
在求完最小生成树之后, 两点的路径就唯一了, 这以后就可以通过倍增 lca
/ 树链剖分求出路径上的最大值即可.
代码链接.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步