CF1214H Tiles Placement

[题目链接] :

https://codeforces.com/contest/1214/problem/H

[题解] :

首先判断不合法的情况 :

CF1214H Tiles Placement

如图 , 若 \(a + b \geq k - 1 , b + c \geq k - 1 , a + c \geq k - 1\) , 显然没有任何一种方案可以满足条件。

这种情况可以通过动态规划判断。

可以证明 , 除了这种情况 , 其它情况都是合法的。 下面给出一种具体的构造方案。

\(1.\) 找出树的直径。

\(2.\) 将树的直径平均分为两部分。

\(3.\) 将直径上的点用 \(1 , 2 , 3 , ... k , 1 , 2 , 3 , ... k\) 交替染色。 不在直径上的点 , 如果在直径的左侧部分 , 那

么就用 \(k , k - 1 , ... 1\) 递减染色 , 否则用 \(2 , 3 , ... k\) 递增染色。

如图 :

CF1214H Tiles Placement

下面证明这个构造的正确性 , 考虑反证 , 设有一条路径不合法。

CF1214H Tiles Placement

情况 \(1\) : 不合法的路径与直径不交 , 如图 , 由直径的性质 , 蓝色部分的长度比 \(v\) 左右两侧的路径都要长。 因此这样的情况

根本不存在。

CF1214H Tiles Placement

情况 \(2\) : 不合法的路径与直径一侧有交。 这样的情况也不存在 , 和情况 \(1\) 类似。

CF1214H Tiles Placement

情况 \(3\) : 不合法的路径跨过直径的两部分 , 那么根据刚才的染色方案 , 这样的情况不可能发生。

时间复杂度 : \(O(N)\)

[代码]

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

#define rep(i , l , r) for (int i = (l); i < (r); ++i)

const int MN = 5e5 + 5;

struct Edge {
	int to , nxt;
} E[MN << 1];

int N , K , r1 , r2 , d1 , d2 , tot;
int head[MN] , s1[MN] , s2[MN];

inline void AddEdge(int u , int v) {
	E[++tot] = (Edge) {v , head[u]};
	head[u] = tot;
}
inline void dfs1(int x , int fa , int dep) {
	if (dep > d1) r1 = x , d1 = dep;
	for (int i = head[x]; i; i = E[i].nxt) if (E[i].to != fa)
		dfs1(E[i].to , x , dep + 1);
}
inline void dfs2(int x) {
	if (s1[x] > s1[r2]) r2 = x;
	for (int i = head[x]; i; i = E[i].nxt) if (!s1[E[i].to]) {
		s1[E[i].to] = s1[x] + 1;
		dfs2(E[i].to);
	}
} 
inline void dfs3(int x) {
	for (int i = head[x]; i; i = E[i].nxt) if (!s2[E[i].to]) {
		s2[E[i].to] = s2[x] - 1;
		dfs3(E[i].to);
	}
}

int main() {
	 
	 scanf("%d%d" , &N , &K);
	 for (int i = 1; i < N; ++i) {
	 	 int u , v;
	 	 scanf("%d%d" , &u , &v);
	 	 AddEdge(u , v); AddEdge(v , u); 
	 }	 
	 dfs1(1 , 0 , 1);
	 s1[r1] = 1; dfs2(r1);
	 s2[r2] = s1[r2]; dfs3(r2);
	 for (int i = 1; i <= N; ++i)
	 	 if (s1[i] >= K && s2[r2] - s2[i] + 1 >= K && s1[i] % K != s2[i] % K) {
			puts("No");
			return 0;
		}
	 puts("Yes");
	 for (int i = 1; i <= N; ++i) {
		 if (s1[i] >= s2[r2] - s2[i] + 1) printf("%d" , (s1[i] - 1) % K + 1);
		 else printf("%d" , (s2[i] - 1) % K + 1);
		 putchar((i == N) ? '\n' : ' ');
	 } 
     return 0;
}
`
上一篇:回溯Leetcode


下一篇:Android 9.0 SystemUI 下拉状态栏快捷开关