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

CF727F Polycarp's problems 题解


CF727F Polycarp’s problems 题解

题目链接:CF727F Polycarp’s problems

题意

有 $n$ 道题目,每道题目有一个质量 $a_i$ (可正可负),题目按照一定顺序排列。cxy 作为出题人,由于不想让参赛者认为是毒瘤题,因此决定删减一些题目。

不妨设一个参赛者的初始心情为 $q$,他会按照顺序阅读这些题目。每读一道题目,他的心情会随着题目的质量改变。意思是说,如果他读了一道质量为 $b$ 的题目,他的心情就会增加 $b$ (即心情为 $q, q+a_1, q+a_1+a_2, \cdots$)。

如果在读了某些题目后,参赛者的心情变为了负数,则他会立即停止阅读且认为这个题库是毒瘤题

cxy 想知道,为了不让参赛者认为是毒瘤题 (即要使他们的心情时刻保持非负),最少需要 (在题库中) 移除多少道题目 (其余题目的顺序保持不变)。由于 cxy 不知道参赛者的初始心情,但她有 $m$ 次猜测 “ 参赛者的初始心情 $q = b_i$”。

对于她的每次猜测,找到满足条件的移除题目数的最小值。

输入格式

第一行包含两个正整数 $n, m,~(n \leq 750, m \leq 2 \times 10^5)$,表示题库中题目的数量和 cxy 猜测初始心情的次数。

第二行包含 $n$ 个整数 $a_1, a_2, \cdots, a_n,~(|a_i| \leq 10^9)$,表示题目的质量。

第三行包含 $m$ 个非负整数 $b_1, b_2, \cdots, b_m,~(b_i \leq 10^{15})$,表示 cxy 对参赛者的初始心情的猜测。

输出格式

输出 $m$ 行,每行一个整数 $s_i$,表示当 $q = b_i$ 时删除题目的最小值。

嗨害嘿,又是我不会的贪心。。虽然我其实已经想出来一大半了

题目其实可以转化为:

多次询问,每次给定 $a_0$ ,求至少删去几个数可以使所有 $S_i \ge 0$

其中 $S_i$ 为前缀和,即 $S_i = \sum_{j=1}^{i} a_j$

考虑前缀和的本质,其实就是用正的 $a_i$ 去消负的 $a_i$

容易想到,我们会尽可能抵消掉绝对值小的 $a_i(a_i < 0)$

为什么呢?因为我们删除一个负数,无论它绝对值多大,都花费 $1$

到目前为止都是简单的贪心。

那么多次询问怎么处理呢?

我们可以假设询问前 $a_0$ 为 $0$ ,然后找到所有消不掉的负数

然后把这些负数的绝对值做一个前缀和(注意要先按绝对值升序排序!)

因为它给的 $a_0 \ge 0$ ,所以我们直接二分 $a_0$ 能消掉几个,用消不掉的负数的数量减掉就好了

时间复杂度 $O((n + q)\log n)$

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdarg>
#include <cmath>
#include <iomanip>
#include <random>
#include <queue>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N ((int)(2e5+15))

int n,m,o,a[N],c[N];
priority_queue<int> q;
#define ub(arr,n,x) (upper_bound(arr+1,arr+1+n,x)-arr)
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> m;
    for(int i=1; i<=n; i++) cin >> a[i];
    for(int i=n; i; i--)
    {
        if(a[i] < 0) q.push(a[i]);
        else
        {
            while(!q.empty() && a[i] >= 0)
                a[i] += q.top(), q.pop();
            if(a[i] < 0) q.push(a[i]);
        }
    }
    while(!q.empty()) c[++o] = q.top(), q.pop();
    for(int i=1; i<=o; i++) c[i] = -c[i] + c[i-1];
    for(int x; m--; ) cin >> x, cout << o - ub(c,o,x) + 1 << '\n';
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/blog/wufeiyang/solution-cf727f


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