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

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);
}

原文地址:https://www.cnblogs.com/suika/p/8997657.html

时间: 2024-10-29 19:05:51

BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心的相关文章

bzoj1528[POI2005]sam-Toy Cars*&amp;&amp;bzoj1826[JSOI2010]缓存交换

bzoj1528[POI2005]sam-Toy Cars bzoj1826[JSOI2010]缓存交换 题意: Jasio有n个不同的玩具,它们都被放在了很高的架子上,地板上不会有超过k个玩具.当Jasio想玩地板上的其他玩具时,他会自己去拿,如果他想玩的玩具在架子上,他的妈妈则会帮他去拿,当她拿玩具的时候,顺便也会将一个地板上的玩具放上架子使得地板上有足够的空间.他的妈妈知道孩子的p个请求,求通过决定每次换玩具时换下哪个所能使他妈妈架子上拿玩具的次数的最小值.k≤100000,p≤50000

[Codeforces 1295E]Permutation Separation(线段树+贪心)

[Codeforces 1295E]Permutation Separation(线段树+贪心) 题面 给出一个排列\(p_1,p_2,...p_n\).初始时你需要选择一个位置把排列分成左右两个.然后在两个序列间移动元素使得左边序列的所有元素都比右边的所有元素小.给出每个元素\(p_i\)从一个序列移动到另一个序列的代价\(a_i\). 分析 显然最后得到的序列是小的数在一边,大的数在另一边.设从值为\(i\)的元素处分开之后移动代价为\(ans_i\). 一开始假设所有数都移到右边序列,那么

[bzoj1577][Usaco2009 Feb]庙会捷运Fair Shuttle_贪心_线段树

庙会捷运 Fair Shuttle bzoj-1577 Usaco-2009 Feb 题目大意:有一辆公交车从1走到n.有m群奶牛从$S_i$到$E_i$,第i群奶牛有$W_i$只.车有一个容量c.问不走回头路的情况下最多使多少奶牛到达目的地.其中,每一群奶牛不一定都拉走. 注释:$1\le n\le 2\cdot 10^4$,$1\le m\le 5\cdot 10^4$,$1\le c\le 100$. 想法:开始觉得是个裸贪心,但是没法维护.其实是这样的: 我们将所有的奶牛群排序:右端点为

[bzoj4345][POI2016]Korale_堆_贪心_线段树_dfs

bzoj4345 POI2016 Korale 题目链接:https://lydsy.com/JudgeOnline/problem.php?id=4345 数据范围:略. 题解: 由于$k$的范围问题,我们很容易想到优先队列. 至于从每个状态怎么往下一个转移就是这个题的精髓. 我们先考虑第一问: 第一问没有字典序的限制,我们把所有的数按照从小到大排序. 堆里维护二元组$(Sum, id)$表示这种选取方式的和位$Sum$,最大下标为$id$. 它可以转移到$(Sum - a_{id} + a_

【Luogu】P1607庙会班车Fair Shuttle(线段树+贪心)

我不会做贪心题啊--贪心题啊--题啊--啊-- 我真TM菜爆了啊-- 这题就像凌乱的yyy一样,把终点排序,终点相同的按起点排序.然后维护一个查询最大值的线段树.对于一个区间[l,r],如果这个区间已经有的最大值为s,那么这个区间最多还能装下c-s头奶牛. 当然奶牛数量没那么多的话我也是没有办法 最后说一句,奶牛到终点就下车了,可以给别的奶牛腾空间,不计入个数.所以奶牛在车上的区间为[l,r-1]. #include <cstdio> #include <iostream> #in

手套(线段树+贪心)

你现在有N对手套,但是你不小心把它们弄乱了,需要把它们整理一下.N对手套被一字排开,每只手套都有一个颜色,被记为0~N-1,你打算通过交换把每对手套都排在一起.由于手套比较多,你每次只能交换相邻两个手套.请你计算最少要交换几次才能把手套排整齐(只需要手套配对,不需要手套按从小到大的编号排序). 30%的数据N≤9:60%的数据N≤1000:100%的数据N≤200,000. 输入格式 输入第一行一个N,表示手套对数.第二行有2N个整数,描述了手套的颜色.每个数都在0~N-1之间,且每个数字都会出

APIO 2012 守卫 | 差分 / 线段树 + 贪心

题目:luogu 3634 首先把为 0 的区间删去,重新标号,可以差分也可以线段树. 把包含其他线段的线段删去,原因 1 是它没有用,原因 2 下面再说.然后,贪心选取最少的点来满足所有线段,即选取还没有点在上面的线段的右端点.如下图中选取的红色方格. 倘若不删去包含其他线段的线段,如上图中的蓝色虚线,我们在贪心选取点的时候,就会先扫到蓝线的左端点而后扫到第二条红线,按照规则,我们会选择蓝线的右端点 6 号点,接下来扫到第二条红线时,由于它上面并没有点被选取,所以又会选取它的右端点 5 号点,

BZOJ_1828_[Usaco2010 Mar]balloc 农场分配_线段树

Description Input 第1行:两个用空格隔开的整数:N和M * 第2行到N+1行:第i+1行表示一个整数C_i * 第N+2到N+M+1行: 第i+N+1行表示2个整数 A_i和B_i Output * 第一行: 一个整数表示最多能够被满足的要求数 Sample Input 5 4 1 3 2 1 3 1 3 2 5 2 3 4 5 Sample Output 3 分析:把每头牛按右端点升序排序,然后能插就插,我们需要维护一下这段区间剩余空间的最小值,如果最小值大于0说明能放进去.

BZOJ_3252_攻略_线段树+dfs序

Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏<XX 半岛>,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景.所有场景和选择支构成树状 结构:开始游戏时在根节点(共通线),叶子节点为结局.每个场景有一个价值,现在桂马开启攻略之神模式,同 时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的) “为什么你还没玩就知道每个场景的价