Atcoder ARC163C Harmonic Mean

发布时间 2023-07-09 00:36:19作者: lhzawa

首先考虑到分数裂项:\(\frac{1}{x} - \frac{1}{x + 1} = \frac{1}{x\times (x + 1)}\),那就有 \(\frac{1}{x} = \frac{1}{x + 1} + \frac{1}{x\times (x + 1)}\)

于是构造方法就很明显了啊,首先特判一下 \(n = 1, 2\) 的情况,然后写出 \(\frac{1}{2} + \frac{1}{2} = 1\) 的式子,对着其中一个 \(\frac{1}{2}\) 就一直裂项下去。

具体的,\(2\) 个集合 \(P, N\)\(P\) 代表可以裂项的数,\(N\) 代表不能裂项的数,每次从 \(P\) 里取出一个数 \(x\) 并删除 \(x\) 这个元素,若 \(x + 1, x\times (x + 1)\) 都没在 \(P\) 中出现过就把这两个数放到 \(P\) 里,否则说明 \(x\) 不能裂项放入 \(N\)
\(|P| + |N| = n\) 时构造完成,\(P, N\) 中的数即为答案。

// lhzawa(https://www.cnblogs.com/lhzawa/)
// Problem: C - Harmonic Mean
// Contest: AtCoder - AtCoder Regular Contest 163
// URL: https://atcoder.jp/contests/arc163/tasks/arc163_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
int main() {
	function<void ()> solve = []() -> void {
		int n;
		scanf("%d", &n);
		if (n == 2) {
			printf("No\n");
			return ;
		}
		set<int> P, N;
		P.insert(1);
		for (; P.size() + N.size() < (size_t)(n); ) {
			int x = *P.begin();
			P.erase(x);
			if (P.count(x + 1) == 0 && P.count(x * (x + 1)) == 0) {
				P.insert(x + 1), P.insert(x * (x + 1));
			}
			else {
				N.insert(x);
			}
		}
		printf("Yes\n");
		for (int x : P) {
			printf("%d ", x);
		}
		for (int x : N) {
			printf("%d ", x);
		}
		printf("\n");
		return ;	
	};
	int _;
	scanf("%d", &_);
	for (; _; _--) {
		solve();
	}
	return 0;
}