代码源 $C$ 队第 $87$ 周总结

闲话

更坏的阅读体验

总结

日期 星期 \(87\) 周作业 abc479
\(2026.10.5\) 一 \(A,B,C,D,E\)
\(2026.10.4\) 四 \(F\)
\(2025.10.5\) 五 \(G,H\)

感受

题目背景

这周周作业过水,速通!

\(I\) 题想出来了,WA 了好几发,好像做法稍微有些假,但和正解无限接近。恶心的真的不想做了。\(J\) 一开始的加一环节真没想出来,似乎乱搞一下就过了。

题目描述

我 abc 做出了 \(\frac{x}{2}\) 题。因此在 \(m\) 个时刻可以用 \((a_i, b_i)\) 来形容我对 abc 的感受。

由于防止我在 \(m\) 个时刻之后精神状态失常,我必须在打 abc 之前提前更改我的想法!

已知我的总平衡值 \(c = \displaystyle{\sum_{i=1}^m |a_i-b_i|}\),现在我可以提前把这 \(2n\) 个数交换,以求总平衡值不超过 \(k\)。

但我的精神状态已经不平衡了,因此制定的方案容易让自己陷入疯狂之中。请善良的你帮我求出符合要求的最小操作次数。

输入格式

第一行输入两个非负整数 \(m, k\)。

接下来 \(m\) 行,第 \(i+1(1 \le i \le m)\) 行输入两个数 \(a_i, b_i\)。

然后就完了。

输出格式

输出一个整数,表示答案。

输入输出样例

3 0
3 3
2 5
2 5
1

说明/提示

数据规模与约定

对于 \(100 \%\) 的数据,\(1 \le n \le 16,1 \le k, a_i, b_i \le 10^6\)。

题解

本题是在 \(2026.1\) 的模拟赛中场切的题。

我们发现每个 \((a_i, b_i)\) 至多只会被交换一次。

根据数据范围 \(1 \le n \le 16\),可以想到复杂度为 \(O(3^n)\) 的状压 DP。

我们设 \(g_i\) 表示状态压缩数值 \(i\) 的状态下,是否能完成合法交换。

把 \(i\) 的第 \(j\) 位为 \(1\) 的 \((a_j, b_j)\) 都放到一个数组中,排一下序,判断相邻两个之差是否小于等于 \(k\)。若是则说明合法。

设 \(f_i\) 表示状态压缩数值 \(i\) 的状态下,完成合法交换的最小操作次数。

我们称一次交换为“满的”,当这次交换把每个 \((a_i, b_i)\) 都交换了一次,\(g_i\) 表示一次“满的”操作。

则 \(f_i = \min_{j = i 的子集} g_j + f_{i - j}\)。

这题就做完了。

话说今天晚上才打 abc,我怎么知道自己的想法呢?

代码

# include <cmath>
# include <cstdio>
# include <cstring>
# include <algorithm>

# define min(x, y) (x < y? x: y)
int n, m, tot, flag, b[100], f[100000], g[100000];

struct Node {
	int x, y;
} a[100];

bool cmp(Node x, Node y) {
	return x.x < y.x;
}

int main( ) {
	
	scanf("%d %d", &n, &m);
	
	for(int i = 1; i <= n; i++)
		scanf("%d %d", &a[i].x, &a[i].y);
		
	memset(g, 0x3f, sizeof(g));
	for(int i = 1; i < (1 << n); i++) {
		tot = 0, flag = 1;
		for(int j = 1; j <= n; j++)
			if(i & (1 << (j - 1))) {
				b[++ tot] = a[j].x;
				b[++ tot] = a[j].y;
			}
		std::sort(b + 1, b + tot + 1);
		for(int j = 1; j <= tot; j += 2)
			if(abs(b[j] - b[j + 1]) > m)
				flag = 0;
		if(flag == 1)
			g[i] = tot / 2 - 1;
	}
	
	for(int i = 0; i < (1 << n); i++) {
		f[i] = g[i];
		for(int j = i; j > 0; j = ((j - 1) & i))
			f[i] = min(f[i], f[i - j] + g[j]);
	}
	
	if(f[(1 << n) - 1] > 1e9)
		printf("%d\n", -1);
	else
		printf("%d\n", f[(1 << n) - 1]);
	
	return 0;
	
}
posted @ 2026-10-11 14:53  Zdy2075  阅读(10)  评论(0)    收藏  举报