Codeforces Round 143 (Div. 2) C. To Add or Not to Add 题解 前缀和 二分

To Add or Not to Add

题目描述

A piece of paper contains an array of n n n integers a 1 , a 2 , . . . , a n a_{1},a_{2},...,a_{n} a1,a2,...,an. Your task is to find a number that occurs the maximum number of times in this array.

However, before looking for such number, you are allowed to perform not more than k k k following operations — choose an arbitrary element from the array and add 1 1 1 to it. In other words, you are allowed to increase some array element by 1 1 1 no more than k k k times (you are allowed to increase the same element of the array multiple times).

Your task is to find the maximum number of occurrences of some number in the array after performing no more than k k k allowed operations. If there are several such numbers, your task is to find the minimum one.

输入格式

The first line contains two integers n n n and k k k ( 1 < = n < = 1 0 5 1<=n<=10^{5} 1<=n<=105 ; 0 < = k < = 1 0 9 0<=k<=10^{9} 0<=k<=109 ) — the number of elements in the array and the number of operations you are allowed to perform, correspondingly.

The third line contains a sequence of n n n integers a 1 , a 2 , . . . , a n a_{1},a_{2},...,a_{n} a1,a2,...,an ( ∣ a i ∣ < = 1 0 9 ) (|a_{i}|<=10^{9}) (ai<=109) — the initial array. The numbers in the lines are separated by single spaces.

输出格式

In a single line print two numbers — the maximum number of occurrences of some number in the array after at most k k k allowed operations are performed, and the minimum number that reaches the given maximum. Separate the printed numbers by whitespaces.

提示

In the first sample your task is to increase the second element of the array once and increase the fifth element of the array twice. Thus, we get sequence 6 , 4 , 4 , 0 , 4 6,4,4,0,4 6,4,4,0,4, where number 4 4 4 occurs 3 3 3 times.

In the second sample you don’t need to perform a single operation or increase each element by one. If we do nothing, we get array 5 , 5 , 5 5,5,5 5,5,5, if we increase each by one, we get 6 , 6 , 6 6,6,6 6,6,6. In both cases the maximum number of occurrences equals 3 3 3. So we should do nothing, as number 5 5 5 is less than number 6 6 6.

In the third sample we should increase the second array element once and the fifth element once. Thus, we get sequence 3 , 2 , 2 , 2 , 2 3,2,2,2,2 3,2,2,2,2, where number 2 2 2 occurs 4 4 4 times.

题面翻译

题目描述

给定一个长度为 n n n 的序列 a 1 a1 a1, a 2 a2 a2…… a n an an,请你把其中一些数进行若干次 + 1 +1 +1 操作,且操作总次数不超过 k k k,使得原序列中某数出现的次数最多。求操作之后的出现最多的数和它出现的次数。

输入

第一行两个整数 n , k n,k n,k,即序列的长度和操作总次数。第二行为 a 1 a1 a1, a 2 a2 a2…… a n an an

输出

两个整数,分别为出现最多的次数和出现最多的。如果有多个满足条件的数字,输出值最小的一个。

样例 #1

样例输入 #1

5 3
6 3 4 0 2

样例输出 #1

3 4

样例 #2

样例输入 #2

3 4
5 5 5

样例输出 #2

3 5

样例 #3

样例输入 #3

5 3
3 1 2 2 1

样例输出 #3

4 2

原题

Codeforces——传送门
洛谷——传送门

代码

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
typedef long long ll;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n, k;
    cin >> n >> k;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        a[i] += 1e9; // 由于读入的数据存在负数,我们可以通过巧妙地补偿1e9来使数组元素成为非负数
    }
    sort(a.begin(), a.end());
    vector<i64> s(n + 1, 0);
    for (int i = 1; i <= n; i++) // 前缀和
        s[i] = s[i - 1] + a[i];

    auto get_cnt = [&](int idx)
    {
        // 最大次数即[left,idx]区间的最大长度
        // 二分left
        int l = 1, r = idx;
        while (l < r)
        {
            int mid = (l + r) / 2;
            // 达到idx-mid+1个a[idx]值需要补充1LL * a[idx] * (idx - mid + 1) - (s[idx] - s[mid - 1])的差值
            // k>=差值,则满足条件
            if (k >= 1LL * a[idx] * (idx - mid + 1) - (s[idx] - s[mid - 1]))
                r = mid;
            else
                l = mid + 1;
        }
        return idx - l + 1;
    };

    int max_cnt = 0;                   // 某数出现的最大次数
    int ans_num = -1;                  // 取到最大次数的最小数组元素
    for (int idx = 1; idx <= n; idx++) // 遍历数组,确定数组中各个元素可出现的最大次数
    {
        int cur_cnt = get_cnt(idx);
        if (cur_cnt > max_cnt)
        {
            max_cnt = cur_cnt;
            ans_num = a[idx];
        }
    }
    cout << max_cnt << ' ' << ans_num - (int)1e9 << '\n'; // 输出时记得将补偿的1e9减去

    return 0;
}
  • 16
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值