Loading

[NOI2017] 蔬菜 题解

神仙贪心题,我这种蒟蒻只能写一篇题解来 \(\text{orz}\)

思路

很容易发现,我们做这道题时,正着去递推贪心及其困难。

尤其还有一些过期等限制,解决起来及其复杂。

那么我们就能有一个小小的思路:时光倒流

我们从反着来递推贪心。

可以发现,过期这个限制就变成了出现。

是不是瞬间就简单多了。

实现步骤

首先有一个大致的步骤:

  1. 算出第十万天的答案。

  2. 不断往前递推,算出前面所有的贡献,列出答案表。

  3. 最后 \(O(1)\) 查询答案

我们可以从 \(p=10^5\) 开始从后往前推。

首先要记录每个时刻出现那些菜,可以用 \(\text{vector}\)

我们考虑将每一个时刻选的的菜用优先队列来维护。

一开始从 \(\text{vector}\) 加入的菜的值是 \(a_i+s_i\)

因为它是第一次出现。

然后,在循环过程中,每次拿出堆顶最大的值。

我们同样还要记录这个菜有没有被选过。

如果拿出的菜没有被选过,就可以直接把这一个记录答案,剩下的直接\(a_i\) 为权值插入优先队列。

如果拿出的菜被选过了,就能取多少取多少。

注意上述过程的答案全部都是给第十万天加的贡献。

递推非常简单。

每次删掉贡献最少的菜就可以了。

Code

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 100010;

int n , m , k , a[maxn] , s[maxn] , c[maxn] , x[maxn] , ans[maxn];
int p = 100000 , now , sum[maxn] , used[maxn];

queue<pair<int , int> > r;
vector<int> l[maxn];
priority_queue< pair<int , int> > q;
priority_queue< pair<int , int> , vector<pair<int , int> > , greater< pair<int , int> > > q2;

inline int read()
{
    int asd = 0 , qwe = 1; char zxc;
    while(!isdigit(zxc = getchar())) if(zxc == '-') qwe = -1;
    while(isdigit(zxc)) asd = asd * 10 + zxc - '0' , zxc = getchar();
    return asd * qwe;
}

signed main()
{
    // freopen("1.in" , "r" , stdin);
    // freopen("1.out" , "w" , stdout);
    n = read() , m = read() , k = read();
    for(int i = 1;i <= n;i++)
    {
        a[i] = read() , s[i] = read() , c[i] = read() , x[i] = read();
        if(x[i] == 0) l[p].push_back(i);
        else l[min(p , (c[i] + x[i] - 1) / x[i])].push_back(i);
    }
    for(int i = p;i >= 1;i--)
    {
        for(auto j : l[i]) q.push(make_pair(a[j] + s[j] , j));
        if(q.empty()) continue;
        for(int tim = m;tim >= 1 && q.empty() == 0;q.pop())
        {
            int top = q.top().second;
            // cout << top << " " << tim << " " << used[top] << " " << a[top] << " " << s[top] << " " << i << " " << ans[p] << endl;
            if(used[top] == 0)
            {
                tim--;
                ans[p] += (a[top] + s[top]) , sum[top]++ , used[top] = 1;
                if(sum[top] != c[top]) q.push(make_pair(a[top] , top));
            }
            else
            {
                int last = c[top] - (i - 1) * x[top] - sum[top];
                int del = min(last , tim);
                ans[p] += del * a[top] , sum[top] += del , tim -= del;
                if(sum[top] != c[top]) r.push(make_pair(a[top] , top));
            }
        }
        while(!r.empty()) q.push(r.front()) , r.pop();
    }
    for(int i = 1;i <= n;i++)
    {
        now += sum[i];
        if(sum[i] == 1) q2.push(make_pair(a[i] + s[i] , i));
        else if(sum[i] > 1) q2.push(make_pair(a[i] , i));
    }
    for(int i = p - 1;i >= 1;i--)
    {
        ans[i] = ans[i + 1];
        int can_del = now - i * m;
        while(can_del > 0)
        {
            int top = q2.top().second; q2.pop();
            if(sum[top] == 1)
            {
                ans[i] -= (a[top] + s[top]);
                can_del-- , now--;
            }
            else
            {
                int del = min(can_del , sum[top] - 1);
                ans[i] -= a[top] * del;
                can_del -= del , sum[top] -= del , now -= del;
                if(sum[top] > 1) q2.push(make_pair(a[top] , top));
                else if(sum[top] == 1) q2.push(make_pair(a[top] + s[top] , top));
            }
        }
    }
    for(int i = 1;i <= k;i++)
    {
        int x = read();
        cout << ans[x] << endl;
    }
    return 0;
}

posted @ 2022-02-17 16:06  JiaY19  阅读(43)  评论(0编辑  收藏  举报