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;
}
参考文献: