AT5759 ThREE

AT5759 ThREE

一道简单的贪心题.

题目给出一棵树, 边权为 \(1\) , 要将树上的点填上 \(1 \sim n\) , 使得距离为 \(3\) 的两个点上的数满足积和和至少有一个为 \(3\) 的倍数.

很简单, 我们先进行一下黑白染色, 那么距离为 \(3\) 的点的颜色一定不同, 接下来我们分类讨论:

设白点个数为 \(wht\) , 黑点个数为 \(blk\) , \(num1, num2, num3\) 分别代表 \(\mod 3 == 1, 2, 0\) 的数.

  1. 如果 \(wht\)\(blk\) 中有一个 \(\le n / 3\) 那么我们直接把这个颜色的点全都赋成 \(3\) 的倍数, 这样其它的点不管怎么选都合法, 因为任意一对点中至少有一个 \(3\) 的倍数, 乘积合法.
  2. 如果 $wht \ge num1 $ 并且 $ blk \ge num2 $ , 说明我们的黑白点都多于 \(n / 3\) 也就是说只靠乘积我们已经无法造出合法方案了, 那就得利用上和了. 一个 \(\mod n == 1\) 的数和一个 \(\mod n == 2\) 的数的和是合法的. 所以我们就先将这两种数分别填入两种颜色的点, 然后 \(3\) 的倍数随便填.

\(code:\)

#include <bits/stdc++.h>
using namespace std;
int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while (!isdigit(ch)) {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (isdigit(ch)) {
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x * f;
}
const int N = 2e5 + 5, M = 4e5 + 5;
int n, ans[N], num1, num2, num3;
int col[N], wht, blk;
int tot, to[M], nxt[M], head[N];
void add(int u, int v) {
	to[++tot] = v, nxt[tot] = head[u], head[u] = tot;
}
void dfs(int x, int fa) {
	for (int i = head[x]; i; i = nxt[i]) {
		int y = to[i];
		if (y == fa) continue;
		col[y] = !col[x];
		dfs(y, x);
	}
}
void init() {
	n = read();
	for (int i = 1; i < n; i++) {
		int u = read(), v = read();
		add(u, v); add(v, u);
	}
	num1 = num2 = num3 = n / 3;
	if (n % 3 == 1) num1++;
	else if (n % 3 == 2) num1++, num2++;
	dfs(1, 0);
	for (int i = 1; i <= n; i++) {
		if (col[i]) wht++;
		else blk++;
	}
}
void solve1() {
	int now = 1;
	for (int i = 1; i <= n && now <= n; i++) {
		if (col[i]) ans[i] = now, now += 3;
	}
	now = 2;
	for (int i = 1; i <= n && now <= n; i++) {
		if (!col[i]) ans[i] = now, now += 3;
	}
	now = 3;
	for (int i = 1; i <= n && now <= n; i++) {
		if (!ans[i]) ans[i] = now, now += 3;
	}
}
void solve2() {
	int now = 3, opt = 1;
	if (wht <= num3) opt = 0;
	for (int i = 1; i <= n; i++) {
		if (col[i] ^ opt) ans[i] = now, now += 3;
	}
	for (int i = 1; now <= n; i++) {
		if (!ans[i]) ans[i] = now, now += 3;
	}
	now = 1;
	for (int i = 1; now <= n; i++) {
		if (!ans[i]) ans[i] = now, now += 3;
	}
	now = 2;
	for (int i = 1; now <= n; i++) {
		if (!ans[i]) ans[i] = now, now += 3;
	}
}
int main() {
	init();
	if (wht >= num1 && blk >= num2) solve1();
	else solve2();
	for (int i = 1; i <= n; i++) printf("%d ", ans[i]);
	printf("\n");
	return 0;
}
posted @ 2021-09-14 18:41  sshadows  阅读(31)  评论(0编辑  收藏  举报