1 条题解

  • 0
    @ 2025-8-24 22:49:33

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar CashCollectFactory
    这个家伙不懒,但什么都留下了

    搬运于2025-08-24 22:49:33,当前版本为作者最后更新于2023-11-23 22:10:42,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题目大意

    公司里有多种员工,每种员工数量已知。现在有若干个工程待完成,完成每项工程都对各类员工的数目有一定最低要求,且完成每项工程后都会获得一定数目新员工的奖励。求能完成的最多工程数

    题目分析

    由于员工不是消耗品,显然越多越好,且获得员工的时机并不影响以后工程的完成,因此该问题显然满足无后效性。那么贪心算法就已经呼之欲出了!我们只要不停的遍历所有工程,遇到可完成的就直接完成并累加员工数,当任何工程都无法完成时,则输出已完成的工程数,最终的时间复杂度为 n3 n^3 。面对十的五次方规模的数据,显然难以忍受。接下来考虑优化!

    解法优化

    标签思想是 OI 界的重要思想之一,本题更是体现的淋漓尽致。观察到保证 mim_ikik_i 之和均不超过 10510^5,我们应当以此为着手点进行代码迭代,发力数据规模痛点,对题目需求进行归因分析,从而打出一套组合拳,完成对此题目的降维打击!

    具体而言,我们为每一个员工类型开一个标签,数组用于维护这些标签,标签中则存储所有对该类员工有需求的工程序号与需求数量。当该类员工数值有所更新时,在维护得到已达到的为需求数目。此外,我们还需要一个计数数组来记录每个工程的待满足需求数,当待满足要求数为零时,说明该工程已可实施,则可将其放入一个栈或队列中,从而通过维护这个栈或队列来统计答案。注意到 1ti,ui1091 \le t_i, u_i \le 10^9,我们难以开如此巨大的数组,所以考虑离散化或 unorder_map。 最终复杂度为 O(n)O(n),采用离散化的话则是 O(nlogn)O(n \log n),其他具体的实现细节可以移步代码实现,里边的注释还是挺详细的!

    代码实现

    #include<bits/stdc++.h>
    using namespace std;
    struct tagy{
        int gongcid,wnum;
        bool operator < (const tagy &x) const {
            return (wnum==x.wnum) ? gongcid<x.gongcid : wnum<x.wnum;
        }//注意这里的小于号重载
        tagy(int G,int W){
            gongcid=G,wnum=W;
        }
    };
    //构建一个标签结构体,分别记录各个工程序号及需求员工数量。
    struct rwd{
        int kd,nm;
        rwd(int K,int N){
            kd=K,nm=N;
        }
    };
    //构建一个奖励结构体,用于在处理可实施工程时候更新员工数量。
    int n,m,tn1,tn2,ans;
    int cnt[500005];//记录每个工程的待满足需求量
    unordered_map<int,int> ar; //记录每种员工目前的数量
    stack<int> s;//维护目前可实施的全部工程
    map<int,set<tagy> > tgm; 
    vector<rwd> v[500005];
    int main(){
        scanf("%d",&n);
        while(n--){
            scanf("%d%d",&tn1,&tn2);
            ar[tn1]=tn2;
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%d",&n);
            int t=0;
            while(n--){
                scanf("%d%d",&tn1,&tn2);
                if(ar[tn1]>=tn2) continue; //若已满足,则忽略。
                tgm[tn1].insert(tagy(i,tn2));
                t++;
            }
            if(!t) s.push(i);
            cnt[i]=t;
            scanf("%d",&n);
            while(n--){
                scanf("%d%d",&tn1,&tn2);
                v[i].push_back(rwd(tn1,tn2));
            }
        }
        while(s.size()){
            ans++; n=s.top(); s.pop();
            for(int i=0;i<v[n].size();i++){
                ar[v[n][i].kd]+=v[n][i].nm;
                while(1){
                	if(tgm[v[n][i].kd].size()==0) break; 
                    set<tagy>::iterator IT;
                    IT=tgm[v[n][i].kd].begin();
                    if((IT->wnum) > ar[v[n][i].kd]) break;
                    cnt[IT->gongcid]--;
                    if(cnt[IT->gongcid]==0) s.push(IT->gongcid);
                    tgm[v[n][i].kd].erase(IT);
                }
            }
        }
        cout<<ans;
        return 0;
    }
    

    需要注意的是,本参考代码使用了 unordered_map,因此需要 C++11 及以上版本。

    PS.记得雁过留声啊

    • 1

    信息

    ID
    9092
    时间
    2000ms
    内存
    1024MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者