[NOI 2017]蔬菜

Description

题库链接

小 N 是蔬菜仓库的管理员,负责设计蔬菜的销售方案。

在蔬菜仓库中,共存放有 $n$ 种蔬菜,小 N 需要根据不同蔬菜的特性,综合考虑各方面因素,设计合理的销售方案,以获得最多的收益。

在计算销售蔬菜的收益时,每销售一个单位第 $i$ 种蔬菜,就可以获得 $a_i$ 的收益。

特别地,由于政策鼓励商家进行多样化销售,第一次销售第 i 种蔬菜时,还会额外得到 $s_i$ 的额外收益。

在经营开始时,第 $i$ 种蔬菜的库存为 $c_i$ 个单位。

然而,蔬菜的保鲜时间非常有限,一旦变质就不能进行销售,不过聪明的小 N 已经计算出了每个单位蔬菜变质的时间:对于第 $i$ 种蔬菜,存在保鲜值 $x_i$ ,每天结束时会有 $x_i$ 个单位的蔬菜变质,直到所有蔬菜都变质。(注意:每一单位蔬菜的变质时间是固定的,不随销售发生变化)

形式化地:对于所有的满足条件 $d \times x_i \leqslant ci$ 的正整数 $d$ ,有 $x_i$ 个单位的蔬菜将在第 $d$ 天结束时变质。

特别地,若 $(d - 1) \times x_i \leqslant c_i \leqslant d \times x_i$ ,则有 $c_i - (d - 1) \times x_i$ 单位的蔬菜将在第 $d$ 天结束时变质。

注意,当 $x_i = 0$ 时,意味着这种蔬菜不会变质。

同时,每天销售的蔬菜总量也是有限的,最多不能超过 $m$ 个单位。

现在,小 N 有 $k$ 个问题,想请你帮忙算一算。每个问题的形式都是:对于已知的 $p_j$ ,如果需要销售 $p_j$ 天,最多能获得多少收益?

$1\leq n,k,p_i\leq 100000,1\leq m\leq 10,0<a_i,c_i\leq 10^9,0\leq s_i,x_i\leq 10^9$

Solution

可以倒着做,从后往前贪。我们先计算 $p=maxp=100000$ 。

由于有额外收益,我们可以将一个蔬菜分成前 $c_i-1$ 个 $a_i$ ,最后 $1$ 个 $a_i+s_i$ 。

这样题目模型就从蔬菜坏掉转化为了一个“进货”操作。

优先队列来解决。

考虑如何求其余的 $p$ 。我们同样倒推。

因为前 $p$ 天推到前 $p-1$ 天时第 $p$ 天买的一定能够在前 $p-1$ 天买。所以同样开一个小根堆,控制堆的大小只有 $mp$ 即可。

Code

#include <bits/stdc++.h>
#define pb push_back
#define ll long long
using namespace std;
const int N = 100000+5, MAXP = 100000;

int n, m, k, a[N], s[N], c[N], x[N], used[N], p;
vector<int> veg[N];
vector<int>::iterator it;
struct node {
    int val, id;
    bool operator < (const node &b) const {return val < b.val; }    
} t;
priority_queue<node> Q;
priority_queue<int, vector<int>, greater<int> > PQ;
queue<int> P;
ll tol, ans[N];

void work() {
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= n; i++) scanf("%d%d%d%d", &a[i], &s[i], &c[i], &x[i]);
    for (int i = 1; i <= n; i++) {
        if (x[i] == 0) veg[MAXP].pb(i);
        else veg[min(MAXP, (c[i]+x[i]-1)/x[i])].pb(i);
    }
    for (int i = MAXP; i >= 1; i--) {
        for (it = veg[i].begin(); it != veg[i].end(); it++)
            Q.push((node){a[*it]+s[*it], *it});
        for (int lim = m; lim && !Q.empty(); --lim, Q.pop()) {
            t = Q.top();
            if (used[t.id] == 0) {
                tol += t.val; ++used[t.id], PQ.push(t.val);
                Q.push((node){a[t.id], t.id});
            }else {
                if (c[t.id]-1ll*x[t.id]*(i-1) > used[t.id]) {
                    tol += t.val; ++used[t.id], PQ.push(t.val);
                    Q.push((node){a[t.id], t.id});
                }else P.push(t.id), ++lim;
            }
        }
        while (!P.empty()) {
            int u = P.front(); P.pop();
            if (used[u] != c[u]) Q.push((node){a[u], u});
        }
    }
    ans[MAXP] = tol;
    for (int i = MAXP-1; i >= 1; i--) {
        while (PQ.size() > 1ll*i*m) tol -= PQ.top(), PQ.pop();
        ans[i] = tol;
    }
    while (k--) {scanf("%d", &p); printf("%lld\n", ans[p]); }
}
int main() {work(); return 0; }
posted @ 2018-07-11 14:31  NaVi_Awson  阅读(305)  评论(0编辑  收藏  举报