CCF 201909-4 推薦系統


CCF 201909-4 推薦系統

試題編號: 201909-4
試題名稱: 推薦系統
時間限制: 5.0s
內存限制: 512.0MB
問題描述:


算法設計

  由於我們需要選出得分最大的K件商品,得出相同的先按類號從小到大排序,再按編號從小到大排序。那么我們可以將所有商品放入到一個set變量bbt中進行自動排序。另外,同類商品編號必然不同,不同類商品編號可能相同,所以我們可以用類號+編號來唯一標識一件商品。由於商品的編號在10^9 以內,而類號在以內,我們可以用類號∗109+編號 類號*10^9+編號類號∗10 ^9+編號來作為一件商品唯一的id,顯然每件商品和其id是一一對應的。這樣的id可以用long long類型存儲,且按id從小到大排序就相當於題目要求的“先按類號從小到大排序,再按編號從小到大排序”的排序原則。如果我們得到一件商品的id,那么這件商品的類號=id/10^9,編號=id%10^9 。

  於是我們可以定義一個商品類dat,其中定義兩個成員變量:id和score。為了方便set排序,需要在類內重載<運算符,保證商品先按得分從大到小排序,再按id從小到大排序。但是這又需要考慮另一個問題,題目中需要對商品進行添加和刪除,添加和刪除操作都是通過商品的id來操作的,我們顯然無法在set中我們需要給出id和score兩個變量才能查找到一件商品,而無法只通過商品的id查找到相應的商品。怎么辦呢?我們可以另外定義一個unordered_map變量um,鍵存儲商品的id,值存儲指向這件商品在set中的位置的迭代器。還記得set中進行插入的insert函數嗎?其實這個函數是有返回值的,只不過我們不常用。它的返回值是一個pair,first成員就是指向新插入的元素在set中位置的迭代器,second成員是一個bool表示這次插入操作是否成功。於是我們在向set中插入商品時可以直接通過代碼um[a] = bbt.insert(dat(a, score)).first;完成um和bbt的同步更新。進行刪除時,我們先通過um找到商品在set中的迭代器,然后利用set的erase函數進行刪除,另外別忘了同步對um中的對應元素也進行刪除就可以了。

  然后是打印操作,我們可以定義一個變量k存儲要選出的最多商品總數,定義一個數組變量K存儲每類商品被選中的最多件數,定義一個二位數組變量ans存儲每類商品要輸出的編號。遍歷整個set,假設當前遍歷到的商品所屬類別為t,而ans[t][0]< K[t],表示當前類別還沒有選滿,則將當前商品的編號加入到ans[t][]中,另外令變量k遞減1,判斷k是否變為了0,如果k變為了0,表示商品總數已選夠,即可直接結束遍歷。

最后,題目中要求,同類商品的編號從小到大輸出,需要對ans中每類商品編號排序再輸出即可。

  然而60分之后的數據有問題,如要獲得滿分,請注釋掉第55行用來對要輸出的商品進行排序的代碼

#pragma GCC optimize(3,"Ofast","inline")
#include<set>
#include<vector>
#include<stdio.h>
#include<tr1/unordered_map>
using namespace std;
using namespace tr1;
typedef long long ll;
const ll mul=1e9;
const int M=55;
const int Kn=105;
struct dat{
    ll id;int s;
    dat(ll id=0,int s=0):id(id),s(s){}
    bool operator <(const dat &c) const{
        return s!=c.s?s>c.s:id<c.id;
    }
};
set<dat>bbt; unordered_map<ll,set<dat>::iterator>um;
int K[M],ans[M][Kn];
int main(){
    int n,m,cas,opt,t,id,s,k;
    scanf("%d%d",&m,&n);
    for(int i=0;i<n;i++){
        scanf("%d%d",&id,&s);
        for(int j=0;j<m;j++){
            ll a=j*mul+id;
            um[a]=bbt.insert(dat(a,s)).first; 
        }
    }
    for(scanf("%d",&cas);cas--;){
        scanf("%d",&opt);
        if(opt==1){
            scanf("%d%d%d",&t,&id,&s);
            ll a=t*mul+id;
            um[a]=bbt.insert(dat(a,s)).first;
        }
        else if(opt==2){
            scanf("%d%d",&t,&id);
            ll a=t*mul+id;
            bbt.erase(um[a]);um.erase(a);
        }
        else{
            scanf("%d",&k);
            for(int i=0;i<m;i++) scanf("%d",&K[i]),ans[i][0]=0;
            for(auto &i:bbt){
                t=i.id/mul;
                if(ans[t][0]<K[t]){
                    ans[t][++ans[t][0]]=i.id%mul;
                    if(!--k) break;
                }
            }
            for(int i=0;i<m;i++){
                if(!ans[i][0]){puts("-1");continue;}
//                sort(ans[i]+1,ans[i]+ans[0]+1)''
                for(int j=1;j<=ans[i][0];j++) printf("%d ",ans[i][j]);
                puts("");
            }
        }
    }
    return 0;
}

----------------------------------------------------------------------------------------------------------------------------

以上是來自網路的做法,以下是來自本人的(原創)做法

----------------------------------------------------------------------------------------------------------------------------

 

 其實大同小異。當然,我的做法在常數上效率更高,不然,我也沒有必要講他了。

/*
建立一個set群:bst[M]。bst[i]的表示維護第i類商品的set
題目保證:任意時刻,同類的任意兩個商品的編號各不相同 
所以可以這樣哈希映射 ha[當前類][該商品id]-->該商品得分,
插入:在當前類的set中插入dat(該商品得分,該商品id) 
刪除:在當前類的set中刪除dat(ha[當前類][該商品id]即該商品得分,該商品id)  
    因為set刪除要么使用迭代器,要么使用無重(包含各項信息的)鍵值 
查詢: 1、if(sum<=K) 只需將所有bst[i]的信息排序輸出
       2、否則,將所有bst[i]的前K大輸出。具體操作如下:
           <1>首先將所有bst[i]的最大扔到堆q中,同時在所有set[i]中刪除該值.
           <2>將堆頂元素x彈出,並將元素x所屬的bst[j]的當前最大y扔到堆q中,同時在set[j]中刪除y.
           <3>重復<2>K次 
*/
#include<set>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<tr1/unordered_map>
#include<iostream>
#include<algorithm>
#define debug(x) cerr<<#x<<" "<<x<<endl;
using namespace std;
using namespace std::tr1;
const int N=1e5+5;
const int M=50+5;
const int Kn=100+5;
int n,m,as,sum,k[M];pair<int,int>vp[N];
unordered_map<int,int>ha[M];
int ans[M][Kn];
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
} 
struct dat{
    int v,id;
    dat(int _v=0,int _id=0):v(_v),id(_id){}
    bool operator <(const dat &a)const{
        return v!=a.v?v>a.v:id<a.id;
    }
};
struct add{
    dat mes;int typ;
    add(dat _mes=0,int _typ=0):mes(_mes),typ(_typ){}
    bool operator <(const add &a)const{
        return mes.v==a.mes.v?typ>a.typ:mes.v<a.mes.v;
    }
};
typedef set<dat> bbt;
bbt bst[M];
bbt::iterator it[M],ed[M];
int cnt;
int main(){
    m=read();n=read();
    for(int i=1,x,y;i<=n;i++) x=read(),y=read(),vp[i]=make_pair(y,x);
    #define x first
    #define y second
    for(int i=0;i<m;i++){
        for(int j=1;j<=n;j++){
            bst[i].insert(dat(vp[j].x,vp[j].y));
            ha[i][vp[j].y]=vp[j].x;
        }
    }
    #undef x
    #undef y
    int op,tpy,com,sco,K,t;
    for(as=read();as--;){
        op=read();
        if(op==1){
            tpy=read();com=read();sco=read();
            bst[tpy].insert(dat(sco,com));
            ha[tpy][com]=sco;
        }
        if(op==2){
            tpy=read();com=read();
            if(t=ha[tpy][com]) bst[tpy].erase(dat(t,com)),ha[tpy][com]=0; 
        }
        if(op==3){
            K=read();sum=0;
            for(int i=0;i<m;i++) k[i]=read(),sum+=k[i];
            for(int i=0;i<m;i++) it[i]=bst[i].begin(),ed[i]=bst[i].end();
            if(sum<=K){
                for(int i=0;i<m;i++) ans[i][0]=0;
                for(int i=0;i<m;i++){
                    for(;k[i];k[i]--){
                        if(it[i]==ed[i]) break;
                        ans[i][++ans[i][0]]=it[i]++->id;
                    }
                    if(!ans[i][0]){puts("-1");continue;}
//                    sort(ans[i]+1,ans[i]+ans[i][0]+1);
                    for(int j=1;j<=ans[i][0];j++) printf("%d ",ans[i][j]);
                    puts("");
                }
            }
            else{
                priority_queue<add> q;int cat=0;
                for(int i=0;i<m;i++) if(it[i]!=ed[i]) q.push(add(*it[i]++,i));
                for(int i=0;i<m;i++) ans[i][0]=0;
                while(!q.empty()){
                    add now=q.top();q.pop();
                    #define typ now.typ
                    #define com now.mes.id
                     if(k[typ]>0){
                        ans[typ][++ans[typ][0]]=com;
                        ++cat; 
                        if(cat==K) break;
                        k[typ]--;
                        if(k[typ]>0&&it[tpy]!=ed[tpy]) q.push(add(*it[typ]++,typ));
                    }
                    #undef typ
                    #undef com
                }
                for(int i=0;i<m;i++){
                    if(!ans[i][0]){puts("-1");continue;}
//                    sort(ans[i]+1,ans[i]+ans[i][0]+1);
                    for(int j=1;j<=ans[i][0];j++) printf("%d ",ans[i][j]);
                    puts("");
                }
            }
        }
    }
    return 0;
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM