Gym - 101778B Ran and the Lock Code丨二分

Gym - 101778B Ran and the Lock Code

题意

让你构造n个数,它们的平均数要是a,求构造的数列最多有多少个不同的数。

思路

我花了很长时间才克服了一个思维定式:

首先很容易想到,\(1 \leftrightarrow 2a-1\)对称分布的数字是都可以的,所以,\(n\leq2a-1\)的答案就是\(n\),大于的就是\(2a-1\)

然后看以下样例,没问题,就这么写了然后就wa了。

为什么呢?可以这样考虑,\(n\)比较大的时候:$${1,\cdots, a-1, a ,a+1,\cdots ,2a-1,\cdots ??? }$$

一个关键点在于,右边还有\(n-(2a-1)\)个位置,这里填什么?

全填\(a\)?,但是如果填入\(\{ 1,a-1,2a \}\) 可以发现,平均数不会变,但是多了一个新的数,\(\{ 2a \}\)

也就是说后面这几个位置怎么安排是一个很复杂很抽象的问题,那我们想一下如何验证某个情况可不可行。

假设当前我猜可以构造出的不同数有\(m\)个,为了数字尽可能多,肯定要包括\(\{1\cdots m\}\)

显然\(m=2a-1\)时候就是我们之前想的非常理想的情况。

因为平均之后总和要等于\(a\times m\)所以我们可以这样检测:

\[(m+1)\times m \div2-a\times m$$就是说这$m$个数总和比全$a$要多出多少, 这些多出来的,我们还剩下$n-m$个数可以去凑,看看能否凑齐就可以了。 于是我们就有个方程,可以验证是单调的,二分来做即可。 ## 代码 ```cpp #include <bits/stdc++.h> #define _debug(x) cerr<<#x<<" = "<<(x)<<endl;fflush(stdout) #define cvint const vint & #define cint const int & using namespace std; typedef long long ll; typedef vector<int> vint; const int maxn = 505; const int inf = 0x3F3F3F3F; const int mod = 1e9 + 7; int Kase; int n, a, ans; inline bool chek(const ll &m) { // return (m + 1) * m / 2 - m * a <= (n - m) * (a - 1); return 2ll * n - m <= 2ll * a * n - m * m; } int main() { scanf("%d", &Kase); while (Kase--) { scanf("%d %d", &n, &a); if (n <= 2 * a - 1) { printf("%d\n", n); continue; } int l = 1, r = n, m; while (l <= r) { m = l + r >> 1; if (chek(m)) { ans = m; l = m + 1; } else { r = m - 1; } } printf("%d\n", ans); } return 0; } /* 9 1 2 8 3 7 4 1 2 5 */ ```\]

posted @ 2019-06-29 15:30  伍玖似十九  阅读(197)  评论(0编辑  收藏  举报