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 。ios
因而咱們能夠定義一個商品類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行用來對要輸出的商品進行排序的代碼spa
#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; }
----------------------------------------------------------------------------------------------------------------------------debug
以上是來自網路的作法,如下是來自本人的(原創)作法設計
----------------------------------------------------------------------------------------------------------------------------3d
其實大同小異。固然,個人作法在常數上效率更高,否則,我也沒有必要講他了。code
/* 創建一個set羣:bst[M]。bst[i]的表示維護第i類商品的set 題目保證:任意時刻,同類的任意兩個商品的編號各不相同 因此能夠這樣哈希映射 ha[當前類][該商品id]-->該商品得分, 插入:在當前類的set中插入dat(該商品得分,該商品id) 刪除:在當前類的set中刪除dat(ha[當前類][該商品id]即該商品得分,該商品id) 由於set刪除要麼使用迭代器,要麼使用無重(包含各項信息的)鍵值 查詢: 一、if(sum<=K) 只需將全部bst[i]的信息排序輸出 二、不然,將全部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; }