CF1862D 题解

洛谷传送门 & CF 传送门

思路

首先我们来讨论一下最优策略。我们设最终的数字有 xx 种,则这 xx 种数字每种一个能组成 x×(x1)÷2x\times(x-1)\div2 个二元组。最优策略就是用贪心的思路,我们肯定是在 x×(x1)÷2nx\times(x-1)\div2\le n 的情况下,让 xx 尽量大,毕竟种数多增长才快。但题目要求正好nn 个二元组,那剩下的 nx×(x1)÷2n-x\times(x-1)\div2 是哪里来的呢?自然是有相同数字。如果有两个相同数字,只会增加一对二元组,而如果有更多个相同数字则不会再增加,所以对于每个数字,我们最多只会有两个相同数字,所以答案就是原先的 xx 个再加上剩下的重复数字个数 nx×(x1)÷2n-x\times(x-1)\div2 了。

我们还要计算 xx。直接从 11 开始枚举 xx,直到不满足 x×(x1)÷2nx\times(x-1)\div2\le n 的时候才结束循环的方法肯定会超时,所以我们可以二分答案。

二分的右边界不能直接定 nn,因为 n1018n\le10^{18},如果直接定 nn 的话二分 check 的时候 mid×(mid1)÷2mid\times(mid-1)\div2 会爆 long long,所以可以使用样例给的最大答案 26489564212648956421

代码

# include <bits/stdc++.h>
typedef long long ll; //不开 ll 见祖宗
using namespace std;
ll t, n, ans, m, l, r, mid;
ll f () {
	cin >> n;
	m = n * 2;
	ans = l = 2, r = 2648956421;
	while (l <= r) { //二分
		mid = l + r >> 1;
		if (mid * (mid - 1) > m)
			r = mid - 1;
		else
			l = mid + 1, ans = mid;
	}
	return ans + n - ans * (ans - 1) / 2;
}
int main () {
	cin >> t;
	while (t --)
		cout << f () << '\n';
	return 0;
}
posted @ 2023-08-25 21:23  Vitamin_B  阅读(16)  评论(0)    收藏  举报  来源