• [NOI2017]蔬菜(贪心+递推)


    这题很有思维难度,乍一看基本无从下手。

    给每个蔬菜钦定退役的时间显然很困难,可以考虑让时光倒流,从后向前递推,然后就变成了某个时间点有一部分蔬菜服役,而已经服役的蔬菜不会退役了。然后就可以直接考虑贪心,每种第一个出现的蔬菜,显然可以单独考虑,加上s[i],然后把蔬菜放到堆里面,就可以在O(pmlogn)的复杂度下求出f[p]了,用堆维护即可,假定p=1e5。

    然后发现这个玩意可以递推求解,第p-1天在役的蔬菜一定不少于第p天的,显然只需去掉利润最少的m个即可。

    #include<bits/stdc++.h>
    #define pb push_back
    using namespace std;
    const int N=1e5+7;
    typedef long long ll;
    typedef pair<int,int>pii;
    struct node{int v,x;}st[N];
    bool operator<(node a,node b){return a.v<b.v;}
    int n,m,T,P=1e5,top,sum,a[N],s[N],c[N],x[N],used[N];
    ll ans[N];
    bool vis[N];
    vector<int>d[N];
    priority_queue<node>q;
    int main()
    {
        scanf("%d%d%d",&n,&m,&T);
        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])d[P].pb(i);else d[min(P,(c[i]+x[i]-1)/x[i])].pb(i);
        for(int i=P;i;i--)
        {
            for(int j=0;j<d[i].size();j++)q.push((node){a[d[i][j]]+s[d[i][j]],d[i][j]});
            if(q.empty())continue;
            int j=m;
            while(j&&!q.empty())
            {
                node u=q.top();q.pop();
                if(!vis[u.x])
                {
                    vis[u.x]=1,ans[P]+=u.v,used[u.x]++,--j;
                    if(c[u.x]>1)q.push((node){a[u.x],u.x});
                }
                else{
                    int rest=min(j,c[u.x]-used[u.x]-(i-1)*x[u.x]);
                    ans[P]+=1ll*rest*u.v,used[u.x]+=rest,j-=rest;
                    if(used[u.x]!=c[u.x])st[++top]=(node){a[u.x],u.x};
                }
            }
            while(top)q.push(st[top--]);
        }
        while(!q.empty())q.pop();
        for(int i=1;i<=n;i++)sum+=used[i];
        for(int i=1;i<=n;i++)
        if(used[i]==1)q.push((node){-s[i]-a[i],i});else if(used[i])q.push((node){-a[i],i});
        for(int i=P-1;i;i--)
        {
            ans[i]=ans[i+1];
            while(sum>i*m&&!q.empty())
            {
                node u=q.top();
                q.pop(),u.v*=-1;
                if(used[u.x]>1)
                {
                    int rest=min(sum-i*m,used[u.x]-1);
                    used[u.x]-=rest,sum-=rest,ans[i]-=1ll*rest*u.v;
                    if(used[u.x]==1)q.push((node){-a[u.x]-s[u.x],u.x});
                    else q.push((node){-a[u.x],u.x});
                }
                else sum--,used[u.x]--,ans[i]-=u.v;
            }
        }
        for(int i=1,x;i<=T;i++)scanf("%d",&x),printf("%lld
    ",ans[x]);
    }
    View Code
  • 相关阅读:
    归并排序处理复杂对象例子
    Java归并排序的递归与非递归实现
    Java实现一个双向链表的倒置功能
    Node<T> 的作用
    Tomcat控制台总是打印日志问题的解决办法
    git回滚部分文件到某个版本
    ios-deploy was not found
    Ionic3的http请求如何实现token验证,并且超时返回登录页
    Ionic开发遇到的坑整理
    使用gradle命令代替CUBA Studio,启动项目
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/11182453.html
Copyright © 2020-2023  润新知