既然代主席叫窝写题解,窝当然得好好写辣。。
原题:http://codeforces.com/gym/101498/problem/F
思路:
其实最主要的问题是在内存满的时候将谁弹出,也就是让留在内存里面的页面尽可能得发挥作用。。
怎么发挥作用?反正碰到相同页面的能发挥作用了嘛。。对内存里面的所有页面找里他下一个相同页面,删除的时候当然是删除下一个页面最远的那个啦。。
然后貌似不太靠谱?可能很多人都考虑到这种情况,例如有2个内存,请求是123122222这样的,把3打入内存时可能觉得保留2也是个不错的方案?我们不妨这么想,第3个以后的2都是上一个2所作出的贡献而不是第1个2,那这样的话内存里面的页面就只能做一次贡献,而做完贡献他们就会被新页面刷新,这样的话显然要优先保留下一个页面离得比较近的了。。。
保证优先级很显然需要用优先队列,按下一页面位置降序排列。。。然后在实现过程中刷新页面这个操作也是直接插入的,旧页面会在队尾不起作用。。。
原题的参考代码:
#include<bits/stdc++.h> #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,l,r) for(int i=l;i>=r;i--) #define inf 2147483647 #define mem(a) memset(a,0,sizeof(a)) #define ll long long #define NM 100010 #define nm 1000000 #define link(x) for(edge*j=h[x];j;j=j->next) using namespace std; int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } struct tmp{ int next,t; bool operator<(const tmp&o)const{return next<o.next;} }a[NM]; int n,m,h[NM],cnt,ans,c[NM],b[NM]; priority_queue<tmp>q; bool v[NM]; bool cmp(int x,int y){ return b[x]<b[y]; } int main(){ int _=read(); while(_--){ n=read();m=read();ans=0;mem(v);mem(h);mem(a);cnt=0; while(!q.empty())q.pop(); inc(i,1,n)b[i]=read(),c[i]=i; sort(c+1,c+1+n,cmp); inc(i,1,n)if(b[c[i-1]]==b[c[i]])a[c[i]].t=a[c[i-1]].t; else a[c[i]].t=i; dec(i,n,1){ a[i].next=h[a[i].t]?h[a[i].t]:n+1; h[a[i].t]=i; } inc(i,1,n){ if(v[a[i].t]){ q.push(a[i]); continue; } if(cnt==m){ tmp t=q.top();q.pop(); v[t.t]=false;cnt--; } q.push(a[i]);cnt++;ans++;v[a[i].t]++; } printf("%d\n",ans); } return 0; }