嘘~ 正在从服务器偷取页面 . . .

CF1415E New Game Plus! 题解


CF1415E New Game Plus! 题解

题目链接:CF1415E New Game Plus!

题意

你有 \(n\) 个数 \(c_{1 \cdots n}\)\(1\) 个初始为 \(0\) 的计数器 boss bonus

你可以任意选择一个尚未被选择过的 \(c_{i}\),把 boss bonus 加上 \(c_{i}\)

你也有 \(k\) 次机会把 boss bonus 变成 \(0\)

每次「选择数字前的 boss bonus 的和」记为你的收获。求收获的最大值。

注意 \(c_{i}\) 和最后的收获可以为负数。

输入格式

输入的第一行两个整数,分别是 \(n,k\)

输入的第二行 \(n\) 个整数,表示 \(c_{1 \cdots n}\)

输出格式

输出一行,最大收获。

数据范围

\(1 \leq n \leq 5 \times 10^5,0 \leq k \leq 5 \times 10^5,-1 \times 10^6 \leq c_{i} \leq 1 \times 10^6\)

容易发现,这 \(k\) 次机会,其实把 \(c\) 就是分成了 \(k+1\) 个集合。

每个集合的元素都有不上升的性质,否则一定存在一个集合使得这个元素放进去以后答案增大。

因此我们可以维护一个堆,记录这 \(k+1\) 个集合,每次取出值最大的那个堆,往里面塞当前最大的 \(c_i\)

时间复杂度 \(\mathcal{O}(n \log n)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e6 + 16))

int res,a[N];
priority_queue<int> q;
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int n, k; cin >> n >> k;
    for(int i = 1; i <= n; i++) cin >> a[i];
    sort(a + 1, a + 1 + n, greater<int>());
    for(int i = 1; i <= k + 1; i++) q.push(0);
    for(int i = 1; i <= n; i++)
    {
        int sum = q.top(); q.pop();
        res += sum; sum += a[i]; q.push(sum);
    }
    cout << res << '\n';
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/blog/gyh20/solution-cf1415e


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录