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

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 !
评论
  目录