1 条题解

  • 0
    @ 2026-5-5 18:48:52

    容易将题意转化成,每次选最大的 aa 个加 11,然后再将最大的 bb 个减 11,重复操作 dd 次。

    显然只有最开始的 aa 个是会被操作的,其他的贡献就是初始值的平方。只保留最大的 aa 个,每次操作变成选最小的 bab-a 个加 11

    然后就变成了下面这个问题:

    nn 个数,每次给最小的 mm 个数加 11,求操作 kk 次后数列。

    m<n105,k109m<n\le 10^5,k\le 10^9

    要总共给 nn 个数加 mkmk,并且每个数最多加 kk。容易发现,如果存在 x<yx<yxx 加的数没有到 kk,那么 yy 不可能被加任何数,否则不满足每次给最小的加的条件。

    考虑二分答案,判断是否所有小于 midmid 的数都变成 ai+ka_i+kmidmid 的最小值的代价是否 mk\le mk。二分要求出最大的满足条件的 midmid。最后二分出来花了 sumsum 的代价,给 mksummk-sum 个等于 midmid 的数加 11 就行了。

    ::::info[code]

    #include <bits/stdc++.h>
    using namespace std;
    
    namespace z {
    
    #define int long long
    const int N = 5e5 + 5, mod = 1e9 + 7;
    int n, m, x, y, a[N], b[N];
    void main() {
    
        ios::sync_with_stdio(false);
        cin.tie(nullptr);cout.tie(nullptr);
        cin >> n >> m >> x >> y;
        int ans = 0, k = x - y;
        for(int i = 1; i <= n; i++) cin >> a[i];
        sort(a + 1, a + n + 1, greater<int>());
        auto chk = [&](int t) -> bool {
            int sum = 0;
            for(int i = 1; i <= x; i++) {
                sum += max(0ll, min(t - a[i], m));
            }
            return sum <= m * k;
        };
        int l = 0, r = 2e9, t = -1;
        while(l <= r) {
            int mid = l + r >> 1;
            if(chk(mid)) l = mid + 1, t = mid;
            else r = mid - 1;
        }  
        int sum = 0;
        for(int i = 1; i <= x; i++) {
            if(a[i] < t) sum += min(m, t - a[i]), a[i] = min(t, a[i] + m); 
        }
        int rem = m * k - sum;
        for(int i = 1; i <= x && rem; i++) if(a[i] == t) a[i]++, rem--;
        for(int i = 1; i <= n; i++) ans += a[i] * a[i] % mod;
        cout << ans % mod << '\n';
    
    }
    
    #undef int
    
    }
    
    
    int main()
    {
        z::main();
        return 0;
    }
    

    ::::

    • 1

    信息

    ID
    1567
    时间
    2000ms
    内存
    256MiB
    难度
    9
    标签
    递交数
    17
    已通过
    3
    上传者