2025.2.11 CW 模拟赛

题面 & 题解

T1

算法

区间 dp.

思路

T1 sol.png

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\), 同理即可.

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 / 树链剖分求出路径上的最大值即可.

代码链接.

posted @ 2025-02-12 11:02  Steven1013  阅读(16)  评论(0)    收藏  举报