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

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

Gym - 101778B Ran and the Lock Code

题意

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

思路

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

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

然后看以下样例,没问题,就这么写了然后就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,,a1,a,a+1,,2a1,???}

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

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

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

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

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

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

( m + 1 ) × m ÷ 2 − a × m (m+1)\times m \div2-a\times m (m+1)×m÷2a×m就是说这 m m m个数总和比全 a a a要多出多少,

这些多出来的,我们还剩下 n − m n-m nm个数可以去凑,看看能否凑齐就可以了。

于是我们就有个方程,可以验证是单调的,二分来做即可。

代码


#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
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值