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\n",r[i][j]);
            }
        }
        else    printf("-1\n");
    }
}


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;
}

猜你喜欢

转载自www.cnblogs.com/shiliuxinya/p/12032232.html