CF1656D K-good

CF1656D K-good

题目大意

题目链接

对于一个正整数 \(n​\) 和一个正整数 \(k​\),称 \(n​\)\(k​\)-good 的当且仅当 \(n​\) 可以被写成 \(k​\) 个正整数之和,且这 \(k​\) 个正整数除以 \(k​\) 的余数互不相同。

\(T\) 次询问,每次给你一个 \(n\),请你求出任意一个 \(\geq 2\)\(k\) 使得 \(n\)\(k\)-good 的,或告知无解。

数据范围:\(1\leq T\leq 10^5​\)\(1\leq n\leq 10^{18}​\)

本题题解

考虑 \(n​\)\(k​\)-good 的条件。因为题目要求“\(k​\) 个互不相同的正整数”,那么它们至少是 \(1, 2, \dots, k​\)。因为是在 \(\bmod k​\) 意义下考虑这 \(k​\) 个正整数,所以我们还可以给其中任意一个数加上任意个 \(k​\)。所以,题目的要求等价于 \(n​\) 可以被写成这种形式:\(n = 1 + 2 + \dots + k + k \cdot m = \frac{k(k + 1)}{2} + k\cdot m​\),其中 \(m​\) 是任意非负整数。

分类讨论,先考虑 \(k\) 是偶数的情况。那么相当于 \(n = \frac{k}{2} \cdot k + \frac{k}{2} + k\cdot m = k\left(\frac{k}{2} + m\right) + \frac{k}{2}\)。进而可以拆成两个条件:

  1. \(n \bmod k = \frac{k}{2}\)
  2. \(\frac{n - \frac{k}{2}}{k} \geq \frac{k}{2}​\),即 \(n \geq \frac{k}{2}\cdot (k + 1)​\)

先考虑第 1 个条件。它相当于:\(k\)\(2n\) 的约数,且不是 \(n\) 的约数。那么显然这就和 \(n\) 分解质因数后“\(2\)”的次数息息相关了。将 \(n\)\(2\) 的最高次数记为 \(\nu_2(n)\)。那么第 1 个条件等价于:\(k\) 必须是 \(2^{\nu_2(n) + 1}\) 乘以一个 \(n\) 的奇约数这个形式。同时,为了满足第 2 个条件,显然 \(k\) 要越小越好。所以可以令 \(k_1 = 2^{\nu_2(n) + 1}\)

此时检查第 2 个条件,若 \(\frac{k_1}{2} \cdot (k_1 + 1) \leq n​\),那么 \(k_1​\) 就是答案。否则说明偶数的 \(k​\) 无解,只能考虑奇数的情况。

一个巧妙的想法是,令 \(k_2 = \frac{2n}{k_1}\),显然,\(k_2\) 是一个奇数。下面我们将证明,只要 \(k_2 \neq 1\)(题目要求 \(k\geq 2\)),那么 \(k_2\) 一定是满足条件的答案。因为 \(\frac{k_1}{2} \cdot (k_1 + 1) > n\),所以 \(\frac{2n}{k_1} < k_1 + 1\),即 \(k_2 < k_1 + 1\)。又因为 \(k_2\) 是奇数,所以 \(k_2 \leq k_1 - 1\)。所以 \(\frac{k_2(k_2 + 1)}{2} \leq \frac{k_2\cdot k_1}{2} = n\)。又因为 \(n\)\(k_2\) 的倍数,所以 \(n - \frac{k_2(k_2 + 1)}{2} = n - k_2\cdot\frac{k_2 + 1}{2}\) 也一定是 \(k_2\) 的倍数(即 \(k_2 \cdot m\) 的形式)。综上所述,\(k_2\) 满足所有要求。

另外,若 \(k_2 = 1​\),则一定无解。因为前面已经说过,\(k​\) 只能是奇数。同时,\(n​\) 显然又必须是 \(k​\) 的倍数。而 \(k_2 = 1​\) 意味着 \(n​\)\(2​\) 的整数次幂,它没有其它奇约数。所以此时输出 \(-1​\) 即可。

单次询问时间复杂度 \(\mathcal{O}(\log_2 n)\),总时间复杂度 \(\mathcal{O}(T\cdot \log_2n)\)

参考代码

// problem: CF1656D
#include <bits/stdc++.h>
using namespace std;

#define pb push_back
#define mk make_pair
#define lob lower_bound
#define upb upper_bound
#define fi first
#define se second
#define SZ(x) ((int)(x).size())

typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

template<typename T> inline void ckmax(T& x, T y) { x = (y > x ? y : x); }
template<typename T> inline void ckmin(T& x, T y) { x = (y < x ? y : x); }

void solve_case() {
	ll n;
	cin >> n;
	
	int v = 1;
	while (n % (1LL << v) == 0)
		++v;
	
	ll k1 = (1LL << v);
	if (n * 2 / k1 >= k1 + 1) { // 等价于 (k1 * (k1 + 1) / 2 <= n),这样写防止爆 long long
		cout << k1 << endl;
		return;
	}
	
	int k2 = n * 2 / k1;
	if (k2 == 1) {
		cout << -1 << endl;
		return;
	}
	cout << k2 << endl;
}

int main() {
	int T;
	cin >> T;
	while (T--) {
		solve_case();
	}
	return 0;
}
posted @ 2022-04-10 13:17  duyiblue  阅读(100)  评论(0编辑  收藏  举报