BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心
BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心
Description
在计算机中,CPU只能和高速缓存Cache直接交换数据。当所需的内存单元不在Cache中时,则需要从主存里把数据调入Cache。此时,如果Cache容量已满,则必须先从中删除一个。 例如,当前Cache容量为3,且已经有编号为10和20的主存单元。 此时,CPU访问编号为10的主存单元,Cache命中。 接着,CPU访问编号为21的主存单元,那么只需将该主存单元移入Cache中,造成一次缺失(Cache Miss)。 接着,CPU访问编号为31的主存单元,则必须从Cache中换出一块,才能将编号为31的主存单元移入Cache,假设我们移出了编号为10的主存单元。 接着,CPU再次访问编号为10的主存单元,则又引起了一次缺失。我们看到,如果在上一次删除时,删除其他的单元,则可以避免本次访问的缺失。 在现代计算机中,往往采用LRU(最近最少使用)的算法来进行Cache调度——可是,从上一个例子就能看出,这并不是最优的算法。 对于一个固定容量的空Cache和连续的若干主存访问请求,聪聪想知道如何在每次Cache缺失时换出正确的主存单元,以达到最少的Cache缺失次数。
Input
输入文件第一行包含两个整数N和M(1<=M<=N<=100,000),分别代表了主存访问的次数和Cache的容量。 第二行包含了N个空格分开的正整数,按访问请求先后顺序给出了每个主存块的编号(不超过1,000,000,000)。
Output
输出一行,为Cache缺失次数的最小值。
Sample Input
6 2
1 2 3 1 2 3
1 2 3 1 2 3
Sample Output
4
HINT
在第4次缺失时将3号单元换出Cache。
考虑x数某次出现的位置到它下一次出现的位置这段区间。
如果我想要让x不缺失,需要在这段区间里让x进入cache,相当于在这个区间(左开右开)塞一个数。
那么整个序列中,每个位置中最多能塞入m-1个数,因为x这个数已经在cache里了。
然后就变成了另一道题:http://www.cnblogs.com/suika/p/8711400.html
代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 200050 #define ls p<<1 #define rs p<<1|1 int n,m; int t[N<<2],add[N<<2],now[N],tot; struct A { int num,id,v; }a[N]; struct node { int l,r; }b[N]; bool cmp1(const A &x,const A &y){return x.num<y.num;} bool cmp2(const A &x,const A &y){return x.id<y.id;} bool cmp3(const node &x,const node &y) { if(x.r==y.r) return x.l>y.l; return x.r<y.r; } void pushdown(int p) { if(add[p]) { int d=add[p]; add[ls]+=d; t[ls]+=d; add[rs]+=d; t[rs]+=d; add[p]=0; } } void build(int l,int r,int p) { t[p]=m-1; if(l==r) {return ;} int mid=(l+r)>>1; build(l,mid,ls); build(mid+1,r,rs); } int query(int l,int r,int x,int y,int p) { if(x<=l&&y>=r) return t[p]; int mid=(l+r)>>1,re=1<<30; pushdown(p); if(x<=mid) re=min(re,query(l,mid,x,y,ls)); if(y>mid) re=min(re,query(mid+1,r,x,y,rs)); t[p]=min(t[ls],t[rs]); return re; } void update(int l,int r,int x,int y,int v,int p) { if(x<=l&&y>=r) { t[p]+=v; add[p]+=v; return ; } pushdown(p); int mid=(l+r)>>1; if(x<=mid) update(l,mid,x,y,v,ls); if(y>mid) update(mid+1,r,x,y,v,rs); t[p]=min(t[ls],t[rs]); } int main() { memset(t,0x3f,sizeof(t)); scanf("%d%d",&n,&m); int i; for(i=1;i<=n;i++) { scanf("%d",&a[i].num); a[i].id=i; } sort(a+1,a+n+1,cmp1); int j=0;a[0].num=1<<30; for(i=1;i<=n;i++) { if(a[i].num!=a[i-1].num)j++; a[i].v=j; } sort(a+1,a+n+1,cmp2); int ans=n; for(i=n;i>=1;i--) { if(now[a[i].v]) { b[++tot].l=i+1; b[tot].r=now[a[i].v]-1; if(b[tot].l>b[tot].r) tot--,ans--; } now[a[i].v]=i; } sort(b+1,b+tot+1,cmp3); build(1,n,1); for(i=1;i<=tot;i++) { int re=query(1,n,b[i].l,b[i].r,1); if(re>=1) { update(1,n,b[i].l,b[i].r,-1,1); ans--; } } printf("%d\n",ans); }