【贪心】codeforces B. Heidi and Library (medium)

http://codeforces.com/contest/802/problem/B

【题意】

有一个图书馆,刚开始没有书,最多可容纳k本书;有n天,每天会有人借一本书,当天归还;如果图书馆有这个本就直接借到,否则图书馆的人会购买这本书,每本书的价格都是1;如果现在图书馆的书已达上限还需购买,必须舍弃已有的一本书,以后再有人借这本书要重新购买。

问图书馆的人最少要花多少钱购书?

数据范围变成了4000 00.

【思路】

关键是替换原则,每次都替换下一次出现最晚的,因为它占用图书馆的时间最长。

【官方题解】

Here we need to be much more ecient. There are many data structures that one can use. One idea is to
store a queue of remaining requests for each possible book (initializing it at the beginning and removing
requests from the front as they arrive) and an std::set-like structure (based on a balanced binary search
tree; it is also possible to use a priority queue based on a heap) which stores books that are currently at the
library, sorted by their next-request time.

这里我用优先级队列找出每次应该替换哪一个,用队列记录每个图书馆中的元素出现位置的情况,不断更新pq和q。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<string>
  5 #include<cmath>
  6 #include<vector>
  7 #include<algorithm>
  8 #include<queue>
  9 #include<map>
 10 using namespace std;
 11 typedef long long ll;
 12 const int maxn=4e5+5;
 13 int a[maxn];
 14 int b[maxn];
 15 map<int,int> mp;
 16 struct Node
 17 {
 18     int id;
 19     int num;
 20     Node(int iid,int nnum):id(iid),num(nnum){}
 21 };
 22 //根据id排序,优先级队列先pop的是排在后面的,也就是下一次出现最晚的 
 23 bool operator<(Node a,Node b)
 24 {
 25     return a.id<b.id;
 26 }
 27 //每个数都有一个出现位置的队列 
 28 queue<int> q[maxn];
 29 priority_queue<Node> pq;
 30 int vis[maxn];
 31 int n,m;
 32 int main()
 33 {
 34     while(~scanf("%d%d",&n,&m))
 35     {
 36         memset(vis,0,sizeof(vis));
 37         for(int i=1;i<=n;i++)
 38         {
 39             scanf("%d",&a[i]);
 40         } 
 41         int ans=0;
 42         int cnt=0;
 43         int i;
 44         for(i=1;i<=n;i++)
 45         {
 46             if(cnt<m)
 47             {
 48                 if(!vis[a[i]])
 49                 {
 50                     b[++cnt]=a[i];
 51                     vis[a[i]]=1;
 52                     ans++;
 53                 }
 54             }
 55             else
 56             {
 57                 break;
 58             }
 59         }
 60         if(cnt<m)
 61         {
 62             printf("%d\n",ans);
 63             continue;
 64         }
 65         //q[a[k]] 为a[k]从小到大出现位置的队列 ,要从i开始算,以前的都不用记 
 66         for(int k=i;k<=n;k++)
 67         {
 68             q[a[k]].push(k);
 69         }
 70         for(int k=1;k<=cnt;k++)
 71         {
 72             if(!q[b[k]].empty())
 73             {
 74                 pq.push(Node(q[b[k]].front(),b[k]));
 75             }
 76             else
 77             {
 78                 //maxn代表后面不出现 
 79                 pq.push(Node(maxn,b[k]));
 80             }
 81             //b[1,cnt]中记录的始终是当前图书馆的书,每个元素都不同,是一个一一映射 
 82             mp[b[k]]=k;
 83         }
 84         for(;i<=n;i++)
 85         { 
 86             if(!q[a[i]].empty())
 87             {
 88                 q[a[i]].pop();
 89             }
 90             if(!vis[a[i]])
 91             {
 92                 ans++;
 93                 Node node=pq.top();
 94                 pq.pop();
 95                 //根据node.num映射到对应b中的位置 
 96                 int id=mp[node.num];
 97                 vis[b[id]]=0;
 98                 b[id]=a[i];
 99                 vis[a[i]]=1;
100                 //更新后的映射 
101                 mp[a[i]]=id;
102             }
103             //要放在后面,否则会影响前面的pop 
104             if(!q[a[i]].empty())
105             {
106                 pq.push(Node(q[a[i]].front(),a[i]));
107             }
108             else
109             {
110                 pq.push(Node(maxn,a[i]));
111             }
112         }
113         printf("%d\n",ans);
114     }
115     return 0;
116 }
View Code

 

posted @ 2017-05-29 19:37  shulin15  阅读(262)  评论(0编辑  收藏  举报