【优先队列+贪心】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 }