【贪心】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 }