既然代主席叫窝写题解,窝当然得好好写辣。。
原题: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;
}