• ccf-201909-04


     题意:有m个种类,每个种类有n个物品。每个物品有自己的种类、编号、分数。要在所有物品中选出不超过sum个的物品。

    按以下方式选择:①按分数排序,分数大的在前  ②分数相同的,种类小的在前 ③分数相同,种类相同,编号小的在前

    每个种类可以选择的物品数量不得超过count[i]个,总的可以选择的物品数量不得超过sum个

    每个种类一行,输出该种类所选择的物品的编号。如何该种类没有物品被选,则输出-1

    有三种操作:①增加结点  ②删除结点  ③输出所选择的物品编号

    注意:m<=50,n<=30000,但是id<=10^9。虽然物品的种类只有50种,每类物品的个数只有30000,但是物品的编号有10^9个。(编号并不是按物品的个数来计算的)

       操作2只给type和id,所以需要映射。因为id<=1e9,所以用二维数组存a[type][id]=score是不可行的。要用unordered_map映射

    思路:

    ①用 ID = type * 1e9 + id 唯一标识一个物品的编号,用set<Node> s存放所有的物品,在Node里定义 id, score, 以及set的排序方式。set会自动排序,所以不用sort一遍,否则会出错。

    ②用unordered_map<long long, set<Node>:: iterator> Map来存物品的ID和物品在set中的迭代器的映射,用来在删除set内部元素。向set增加元素时,用Map[ID]=s.insert(x).first来获取映射关系,时间复杂度O(1)。如果用遍历set的方法删除元素,O(n),会超时。

    ③用vector来存每个type所选的物品的id。set的结构体里没有存type,id,那么要如何获取type和id?

       因为ID =  type * 1e9 + id,所以type = ID / 1e9,  id = ID % 1e9, 注意:因为ID是long long,所以设置const long long INF = 1e9

    知识点:

    *** insert函数的返回值是一个pair,first成员就是指向新插入的元素在set中位置的迭代器,second成员是一个bool表示这次插入操作是否成功

    ①关联容器包括:set、map
    标准库提供set关联容器分为:
    (1)按关键字有序保存元素:set(关键字即值,即只保存关键字的容器);multiset(关键字可重复出现的set);
    (2)无序集合:unordered_set(用哈希函数组织的set);unordered_multiset(哈希组织的set,关键字可以重复出现)。

    ②在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。set中元素的值不能直接被改变。set内部采用的是一种非常高效的平衡检索二叉树:红黑树,也称为RB树(Red-Black Tree)。RB树的统计性能要好于一般平衡二叉树。

    ③set具备的特点:
    (1)set中的元素都是排序好的
    (2)set中的元素都是唯一的,没有重复的

    ④map:红黑树结构,自动排序

    ⑤map<class T1,class T2> :存储T1->T2映射的键值对,map先按照T1升序排序,再按T2升序排序,其中T1,T2可以是任意类(如:int、string、char或自定义类),T1值唯一,其插入删除的时间复杂度为O(log2)

    ⑥unordered_map<class T1,class T2>特性: 仅存储T1->T2映射的键值对,T1值唯一,其插入和删除的时间复杂度为O(1)

    ⑦unordered_map 无序映射:比map快(用map会超时)

    ⑧unordered_map 在C++ 11 才可以用,否则会编译出错

    #include <bits/stdc++.h> 
    #define MAX 51
    
    using namespace std;
    
    
    struct Node{
        long long id;
        int score;
        bool operator < (const Node &b)    const{                //Set要内部排序,用struct写set,需要在struct内重写排序方法 
            if(score!=b.score)    return    score > b.score;
            else    return id < b.id; 
        }
    };
    
    
    
    set <Node> s;        //用set存放所有物品信息    
    vector<int> r[MAX];
    unordered_map<long long, set<Node>::iterator> Map;        //key:type*10^9 + id;  value:物品在set中的迭代器  ||用type * 1e9 +id 唯一标识一个物品的序号  
    int m;        //物品种类 
    int n;        //物品个数 
    int sum;    //总的不能超过的个数 
    int Count[MAX];        //每类物品不得超过的个数 
    const long long INF = 1e9;      //因为ID是long long,并且要取模,所以要将1e9也设置为long long 
    
    
    
    void op(){
        int cont =0;
        for(int i=0;i<MAX;i++)
            r[i].clear(); 
        for(set<Node>::iterator it =s.begin();  it!=s.end(); it++){
            if(sum==0)    break;
            Node a=*it;
            int type =a.id / 1e9;
            int id =a.id % INF;            //long long % long long
            if(Count[type]>0){        //该种类还可以选 
                Count[type]--;
                r[type].push_back(id);
                sum--;
                }
            }    
        for(int i=0;i<m;i++){
            int len=r[i].size();
            if(len!=0){
                for(int j=0;j<len;j++){
                    if(j!=len-1)    printf("%d ",r[i][j]);
                    else printf("%d
    ",r[i][j]);
                }
            }
            else    printf("-1
    ");
        }
    }
    
    
    int main(){
        int type,id,score,c,q;
        Node x;
        while(scanf("%d %d",&m,&n)!=EOF){
            s.clear();
            memset(Count,0,sizeof(Count));
            for(int i=1;i<=n;i++){
                scanf("%d %d",&id,&score);    
                x.score=score;
                for(int j=0;j<m;j++){
                    x.id=j*1e9 + id;    
                    long long key=j*1e9+id;
                    Map[key]=s.insert(x).first;
                }
            }
            scanf("%d",&q);
            for(int i=0;i<q;i++){
                scanf("%d",&c);
                if(c==1){
                    scanf("%d %d %d",&type,&id,&score);
                    x.id=type*1e9 + id;     x.score=score;
                    long long key=type*1e9+id;
                    Map[key]=s.insert(x).first;        //向Set插入元素 
                }
                else if(c==2){
                    scanf("%d %d",&type,&id);                //set.erase()提供了4种重载,分别可以通过key,或者迭代器,或者迭代器范围来删除元素。
                    long long k=type*1e9+id;
                    s.erase(Map[k]);                //根据元素的迭代器,删除Set中的元素 
                    Map.erase(k);                //删除物品在Map中的映射 
                                                //s.erase(Node{type,id,score});            //为什么出错?                        
                }
                else if(c==3){
                    scanf("%d",&sum);
                    for(int i=0;i<m;i++){
                        scanf("%d",&Count[i]);        //第i个种类不得超过count[i]个 
                    }
                    op();
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    uml 类图
    Java IO流
    Spring 创建Bean的 三种方式
    linux+jmeter+python基础+抓包拦截
    接口测试
    HDU 1159 Common Subsequence(POJ 1458)
    HDU 1160 FatMouse's Speed
    HDU 4540 威威猫系列故事——打地鼠
    HDU 1087 Super Jumping! Jumping! Jumping!
    HDU 1176 免费馅饼
  • 原文地址:https://www.cnblogs.com/shiliuxinya/p/12032232.html
Copyright © 2020-2023  润新知