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行用来对要输出的商品进行排序的代码

  1. #pragma GCC optimize(3,"Ofast","inline")
  2. #include<set>
  3. #include<vector>
  4. #include<stdio.h>
  5. #include<tr1/unordered_map>
  6. using namespace std;
  7. using namespace tr1;
  8. typedef long long ll;
  9. const ll mul=1e9;
  10. const int M=;
  11. const int Kn=;
  12. struct dat{
  13. ll id;int s;
  14. dat(ll id=,int s=):id(id),s(s){}
  15. bool operator <(const dat &c) const{
  16. return s!=c.s?s>c.s:id<c.id;
  17. }
  18. };
  19. set<dat>bbt; unordered_map<ll,set<dat>::iterator>um;
  20. int K[M],ans[M][Kn];
  21. int main(){
  22. int n,m,cas,opt,t,id,s,k;
  23. scanf("%d%d",&m,&n);
  24. for(int i=;i<n;i++){
  25. scanf("%d%d",&id,&s);
  26. for(int j=;j<m;j++){
  27. ll a=j*mul+id;
  28. um[a]=bbt.insert(dat(a,s)).first;
  29. }
  30. }
  31. for(scanf("%d",&cas);cas--;){
  32. scanf("%d",&opt);
  33. if(opt==){
  34. scanf("%d%d%d",&t,&id,&s);
  35. ll a=t*mul+id;
  36. um[a]=bbt.insert(dat(a,s)).first;
  37. }
  38. else if(opt==){
  39. scanf("%d%d",&t,&id);
  40. ll a=t*mul+id;
  41. bbt.erase(um[a]);um.erase(a);
  42. }
  43. else{
  44. scanf("%d",&k);
  45. for(int i=;i<m;i++) scanf("%d",&K[i]),ans[i][]=;
  46. for(auto &i:bbt){
  47. t=i.id/mul;
  48. if(ans[t][]<K[t]){
  49. ans[t][++ans[t][]]=i.id%mul;
  50. if(!--k) break;
  51. }
  52. }
  53. for(int i=;i<m;i++){
  54. if(!ans[i][]){puts("-1");continue;}
  55. // sort(ans[i]+1,ans[i]+ans[0]+1)''
  56. for(int j=;j<=ans[i][];j++) printf("%d ",ans[i][j]);
  57. puts("");
  58. }
  59. }
  60. }
  61. return ;
  62. }

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

以上是来自网路的做法,以下是来自本人的(原创)做法

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

其实大同小异。当然,我的做法在常数上效率更高,不然,我也没有必要讲他了。

  1. /*
  2. 建立一个set群:bst[M]。bst[i]的表示维护第i类商品的set
  3. 题目保证:任意时刻,同类的任意两个商品的编号各不相同
  4. 所以可以这样哈希映射 ha[当前类][该商品id]-->该商品得分,
  5. 插入:在当前类的set中插入dat(该商品得分,该商品id)
  6. 删除:在当前类的set中删除dat(ha[当前类][该商品id]即该商品得分,该商品id)
  7. 因为set删除要么使用迭代器,要么使用无重(包含各项信息的)键值
  8. 查询: 1、if(sum<=K) 只需将所有bst[i]的信息排序输出
  9. 2、否则,将所有bst[i]的前K大输出。具体操作如下:
  10. <1>首先将所有bst[i]的最大扔到堆q中,同时在所有set[i]中删除该值.
  11. <2>将堆顶元素x弹出,并将元素x所属的bst[j]的当前最大y扔到堆q中,同时在set[j]中删除y.
  12. <3>重复<2>K次
  13. */
  14. #include<set>
  15. #include<queue>
  16. #include<cstdio>
  17. #include<algorithm>
  18. #include<tr1/unordered_map>
  19. #include<iostream>
  20. #include<algorithm>
  21. #define debug(x) cerr<<#x<<" "<<x<<endl;
  22. using namespace std;
  23. using namespace std::tr1;
  24. const int N=1e5+;
  25. const int M=+;
  26. const int Kn=+;
  27. int n,m,as,sum,k[M];pair<int,int>vp[N];
  28. unordered_map<int,int>ha[M];
  29. int ans[M][Kn];
  30. inline int read(){
  31. int x=,f=;char ch=getchar();
  32. while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
  33. while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
  34. return x*f;
  35. }
  36. struct dat{
  37. int v,id;
  38. dat(int _v=,int _id=):v(_v),id(_id){}
  39. bool operator <(const dat &a)const{
  40. return v!=a.v?v>a.v:id<a.id;
  41. }
  42. };
  43. struct add{
  44. dat mes;int typ;
  45. add(dat _mes=,int _typ=):mes(_mes),typ(_typ){}
  46. bool operator <(const add &a)const{
  47. return mes.v==a.mes.v?typ>a.typ:mes.v<a.mes.v;
  48. }
  49. };
  50. typedef set<dat> bbt;
  51. bbt bst[M];
  52. bbt::iterator it[M],ed[M];
  53. int cnt;
  54. int main(){
  55. m=read();n=read();
  56. for(int i=,x,y;i<=n;i++) x=read(),y=read(),vp[i]=make_pair(y,x);
  57. #define x first
  58. #define y second
  59. for(int i=;i<m;i++){
  60. for(int j=;j<=n;j++){
  61. bst[i].insert(dat(vp[j].x,vp[j].y));
  62. ha[i][vp[j].y]=vp[j].x;
  63. }
  64. }
  65. #undef x
  66. #undef y
  67. int op,tpy,com,sco,K,t;
  68. for(as=read();as--;){
  69. op=read();
  70. if(op==){
  71. tpy=read();com=read();sco=read();
  72. bst[tpy].insert(dat(sco,com));
  73. ha[tpy][com]=sco;
  74. }
  75. if(op==){
  76. tpy=read();com=read();
  77. if(t=ha[tpy][com]) bst[tpy].erase(dat(t,com)),ha[tpy][com]=;
  78. }
  79. if(op==){
  80. K=read();sum=;
  81. for(int i=;i<m;i++) k[i]=read(),sum+=k[i];
  82. for(int i=;i<m;i++) it[i]=bst[i].begin(),ed[i]=bst[i].end();
  83. if(sum<=K){
  84. for(int i=;i<m;i++) ans[i][]=;
  85. for(int i=;i<m;i++){
  86. for(;k[i];k[i]--){
  87. if(it[i]==ed[i]) break;
  88. ans[i][++ans[i][]]=it[i]++->id;
  89. }
  90. if(!ans[i][]){puts("-1");continue;}
  91. // sort(ans[i]+1,ans[i]+ans[i][0]+1);
  92. for(int j=;j<=ans[i][];j++) printf("%d ",ans[i][j]);
  93. puts("");
  94. }
  95. }
  96. else{
  97. priority_queue<add> q;int cat=;
  98. for(int i=;i<m;i++) if(it[i]!=ed[i]) q.push(add(*it[i]++,i));
  99. for(int i=;i<m;i++) ans[i][]=;
  100. while(!q.empty()){
  101. add now=q.top();q.pop();
  102. #define typ now.typ
  103. #define com now.mes.id
  104. if(k[typ]>){
  105. ans[typ][++ans[typ][]]=com;
  106. ++cat;
  107. if(cat==K) break;
  108. k[typ]--;
  109. if(k[typ]>&&it[tpy]!=ed[tpy]) q.push(add(*it[typ]++,typ));
  110. }
  111. #undef typ
  112. #undef com
  113. }
  114. for(int i=;i<m;i++){
  115. if(!ans[i][]){puts("-1");continue;}
  116. // sort(ans[i]+1,ans[i]+ans[i][0]+1);
  117. for(int j=;j<=ans[i][];j++) printf("%d ",ans[i][j]);
  118. puts("");
  119. }
  120. }
  121. }
  122. }
  123. return ;
  124. }

CCF 201909-4 推荐系统的更多相关文章

  1. CCF认证201909-4推荐系统

    #include <iostream> #include <list> #include <set> #include <vector> using n ...

  2. CCF模拟题-201909

    2.小明种苹果(续)(100分) #include<iostream> #include<cstdio> #include<cstring> #define max ...

  3. CCF 试题编号: 201909-4 试题名称: 推荐系统

    这题是stl的综合应用,map要想快,直接上unordered_map,这样查询接近O(1),是不是很嗨皮. 思路其实还是很简单的,type+id做个Hash,由于set.insert的第一个返回值是 ...

  4. SVD的几何意义,以及在去噪,推荐系统中的应用

    很多文章说到奇异值分解的时候总是大概罗列下它的功能,并没有对功能及物理意义进行过多的阐述,现在我来对奇异值进行整理一下. 一 奇异值分解 对任意的矩阵A∈Fmn,rank(A)=r(矩阵的秩),总可以 ...

  5. F#之旅6 - 简单AV推荐系统

    上回说到用F#来写爬虫,这只是F#学习第一阶段的第一步.最开始,就对第一阶段做了这样的安排: 1.爬虫爬取AV数据 2.数据处理和挖掘 3.数据可视化(使用ECharts) 4.推荐系统 第一步很快就 ...

  6. CCF考试

    第八次CCF考试记录 代码还不知道对不对,过两天出成绩. 成绩出来了,310分. 100+100+100+10+0: 考试13:27开始,17:30结束,提交第4题后不再答题,只是检查前四题的代码 第 ...

  7. [Recommendation System] 推荐系统之协同过滤(CF)算法详解和实现

    1 集体智慧和协同过滤 1.1 什么是集体智慧(社会计算)? 集体智慧 (Collective Intelligence) 并不是 Web2.0 时代特有的,只是在 Web2.0 时代,大家在 Web ...

  8. 推荐相关学习 & 典型算法、典型特征、典型推荐系统框架

    总的来说,信息爆炸,产生了信息过载.解决的方法主要有两类:检索和推荐.检索是主动的有目的的.意图明确,推荐是非主动的.意图不明确. 推荐方面最经典的,就是协同过滤推荐了.我博客这里有两篇,一篇偏理论, ...

  9. 推荐系统学习--cb+cf 初见

    对于推荐系统的推出有两个条件:1.信息过载 ,2用户没有明确的需求 推荐系统算法中常见的有基于内容推荐,协同过滤推荐,协同过滤还可以分为基于人的协同过滤,基于内容协同过滤:社会推荐等 如何理解这些推荐 ...

随机推荐

  1. markdown使用emoji

    前几日写博客的时候在想是否能够在markdown中使用emoji呢

  2. java.net.URLEncoder对中文的编码和解码

    // java.net.URLEncoder对中文的编码和解码String str = URLEncoder.encode("测试字符串", "utf-8"); ...

  3. Computer Networking: A Top Down Approach

    目录 Chapter 1: Computer Networks and the Internet 1. What is the Internet? 2. The Network Edge 3. The ...

  4. js进度条源码下载—js进度条代码

    现在很多网站会用到进入网站特效,到网页没有加载完成的时候,会有一个loding特效,加载完了之后才能看到页面,今天就带着做一个js进度条效果,今天要做的效果是纯js进度条加载,没有用到框架,方便大家进 ...

  5. JS案例 - 分页

    1.html文件 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  6. 解决vue多次提交

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <template>  <button @click="subm ...

  7. Kubernetes学习之路(28)之镜像仓库Harbor部署

    Harbor的部署 官方文档 Harbor有两种安装的方式: 在线安装:直接从Docker Hub下载Harbor的镜像,并启动. 离线安装:在官网上下载离线安装包其地址为:https://githu ...

  8. Nodejs入门级

    应用不同模块分析 我们来分解一下这个应用,为了实现一个应用,我们需要实现哪些部分呢? 我们需要提供Web页面,因此需要一个HTTP服务器 对于不同的请求,根据请求的URL,我们的服务器需要给予不同的响 ...

  9. docker中使用阿里云的apt源安装各种实用工具

    今天想在docker中安装vim工具,还有其他的软件等等,如果你直接执行apt-get install vim是没有用的,会显示: root@7d43d83fd3a8:/etc/nginx# apt- ...

  10. 还是把这道kmp的题po出来吧,省的以后自己也忘了

    做了一个问题突然想到可以用Kmp解决,所以看了一下自己之前写的关于Kmp的博客用JAVA实现的KMP匹配子串,记录一下,省的又忘了. /* *题目描述: * 假定我们都知道非常高效的算法来检查一个单词 ...