Gym - 101778B Ran and the Lock Code丨二分
Gym - 101778B Ran and the Lock Code
题意
让你构造n个数,它们的平均数要是a,求构造的数列最多有多少个不同的数。
思路
我花了很长时间才克服了一个思维定式:
首先很容易想到, 1 ↔ 2 a − 1 1 \leftrightarrow 2a-1 1↔2a−1对称分布的数字是都可以的,所以, n ≤ 2 a − 1 n\leq2a-1 n≤2a−1的答案就是 n n n,大于的就是 2 a − 1 2a-1 2a−1。
然后看以下样例,没问题,就这么写了然后就wa了。
为什么呢?可以这样考虑, n n n比较大的时候: { 1 , ⋯   , a − 1 , a , a + 1 , ⋯   , 2 a − 1 , ⋯ ? ? ? } \{1,\cdots, a-1, a ,a+1,\cdots ,2a-1,\cdots ??? \} {1,⋯,a−1,a,a+1,⋯,2a−1,⋯???}
一个关键点在于,右边还有 n − ( 2 a − 1 ) n-(2a-1) n−(2a−1)个位置,这里填什么?
全填 a a a?,但是如果填入 { 1 , a − 1 , 2 a } \{ 1,a-1,2a \} {1,a−1,2a} 可以发现,平均数不会变,但是多了一个新的数, { 2 a } \{ 2a \} {2a}
也就是说后面这几个位置怎么安排是一个很复杂很抽象的问题,那我们想一下如何验证某个情况可不可行。
假设当前我猜可以构造出的不同数有 m m m个,为了数字尽可能多,肯定要包括 { 1 ⋯ m } \{1\cdots m\} {1⋯m}
显然 m = 2 a − 1 m=2a-1 m=2a−1时候就是我们之前想的非常理想的情况。
因为平均之后总和要等于 a × m a\times m a×m所以我们可以这样检测:
( m + 1 ) × m ÷ 2 − a × m (m+1)\times m \div2-a\times m (m+1)×m÷2−a×m就是说这 m m m个数总和比全 a a a要多出多少,
这些多出来的,我们还剩下 n − m n-m n−m个数可以去凑,看看能否凑齐就可以了。
于是我们就有个方程,可以验证是单调的,二分来做即可。
代码
#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
*/