CodeForces 1379E Inverse Genealogy

发布时间 2024-01-10 11:00:21作者: zltzlt

洛谷传送门

CF 传送门

\(n\) 为偶数显然无解。

否则我们可以构造一棵 \(n\) 个点的完全二叉树,当 \(n + 1\)\(2\) 的幂时满足 \(m = 1\),否则 \(m = 0\)

\(n \ge 5\) 时可以递归至 \((n - 2, m - 1)\),再挂一个叶子即可。

但是可能会出现 \(n + 1\) 不是 \(2\) 的幂,但 \(n - 1\) 是,可能会把有解判成无解。

打一个补丁,如果上面那种情况递归下去无解,当 \(n \ge 11\) 时我们可以接一棵 \(3\) 个点的满二叉树,然后再递归至 \((n - 4, m - 1)\)

时间复杂度 \(O(n)\)

code
// Problem: E. Inverse Genealogy
// Contest: Codeforces - Codeforces Round 657 (Div. 2)
// URL: https://codeforces.com/problemset/problem/1379/E
// Memory Limit: 512 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 100100;

int n, m, a[maxn];

int dfs(int n, int m) {
	if (n <= 1 || m < 0) {
		return -1;
	}
	if ((m == 1 && (1 << (__lg(n) + 1)) != n + 1) || (m == 0 && (1 << (__lg(n) + 1)) == n + 1)) {
		for (int i = 2; i <= n; ++i) {
			a[i] = (i >> 1);
		}
		return 1;
	}
	int r = dfs(n - 2, m - 1);
	if (r != -1) {
		a[r] = a[n - 1] = n;
		return n;
	}
	if (n > 9) {
		a[n - 3] = a[n - 2] = n - 1;
		a[n - 1] = n;
		r = dfs(n - 4, m - 1);
		if (r == -1) {
			return -1;
		}
		a[r] = n;
		return n;
	}
	return -1;
}

void solve() {
	scanf("%d%d", &n, &m);
	if (n == 1) {
		if (m == 0) {
			puts("YES\n0");
		} else {
			puts("NO");
		}
		return;
	}
	if (n % 2 == 0 || m > (n - 3) / 2) {
		puts("NO");
		return;
	}
	if (dfs(n, m) == -1) {
		puts("NO");
		return;
	}
	puts("YES");
	for (int i = 1; i <= n; ++i) {
		printf("%d ", a[i]);
	}
	putchar('\n');
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}