【优先队列+贪心】BZOJ1826-[JSOI2010]缓存交换

……啊开始颓了。

【题目大意】

已知当前集合最大容量为m,n个询问。每次询问一个元素,如果集合中没有则需要加入该元素,如果集合已经满了则需要先删去集合中的某些元素再加入。问至少要加入几次元素?

【思路】

显然每一次删除的元素是下一次出现最晚的那一个,优先队列维护一下就好了。

【错误点】

非常ZZ地把集合满的条件定为了“que.size()==m”,实际上如果该元素已经存在,我们更新下一次出现的时候原来的在优先队列中是不删除的。所以必须另外设一个qsize记录集合中有几个元素存在。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAXN=110000;
 4 typedef pair<int,int> p;
 5 const int INF=0x7fffffff;
 6 int n,m,a[MAXN],d,hash[MAXN];
 7 int rcap[MAXN],nap[MAXN];//recently appear & next appear
 8 priority_queue<p> que;
 9 int inque[MAXN],qsize;
10 
11 void init()
12 {
13     scanf("%d%d",&n,&m);
14     for (int i=1;i<=n;i++) scanf("%d",&a[i]),hash[i]=a[i];
15     sort(hash+1,hash+n+1);
16     d=unique(hash+1,hash+n+1)-(hash+1);
17     for (int i=1;i<=n;i++) a[i]=lower_bound(hash+1,hash+d+1,a[i])-hash;
18     for (int i=1;i<=n;i++) rcap[i]=nap[i]=INF;
19     for (int i=1;i<=n;i++)
20     {
21         if (rcap[a[i]]!=INF) nap[rcap[a[i]]]=i;
22         rcap[a[i]]=i;
23     }
24 } 
25 
26 void solve()
27 {
28     int ans=0;
29     memset(inque,0,sizeof(inque));
30     qsize=0;
31     for (int i=1;i<=n;i++)
32     {
33         if (!inque[a[i]])
34         {
35             if (qsize==m) //这里不能用que.size()代替,因为相同元素可能都在优先队列里呢 
36             {
37                 inque[que.top().second]=0;
38                 que.pop();
39                 qsize--;
40             }
41             inque[a[i]]=1;
42             ans++;
43             qsize++;
44         }
45         que.push(p(nap[i],a[i]));
46     }
47     printf("%d\n",ans);
48 }
49 
50 int main()
51 {
52     init();
53     solve();
54     return 0;
55 }

 

posted @ 2016-11-15 17:31  iiyiyi  阅读(445)  评论(0编辑  收藏  举报