[bzoj1826][贪心]缓存交换

22 篇文章 0 订阅

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。

题解

先离散化再贪心一下
设第i个位置下一个相同的单元是nxt[i],如果没有的话nxt[i]=n+1
那每次弹出肯定是弹出nxt[i]最大的
那你可以搞一个可删堆,维护nxt[i]
然后又是随便做了。。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
struct LSnode{int y,p;}w[110000];
bool cmp(LSnode n1,LSnode n2){return n1.y<n2.y;}
int pla[110000];
struct node
{
    int pla;
    friend bool operator <(node n1,node n2){return n1.pla<n2.pla;}
};
struct heap
{
    priority_queue<node> A,B;
    void push(node x){A.push(x);}
    void pop()
    {
        node tx,ty;
        tx=A.top();
        if(B.size())ty=B.top();
        while(tx.pla==ty.pla && B.size()){A.pop();B.pop();tx=A.top();ty=B.top();}
        A.pop();
    }
    void erase(node x){B.push(x);}
    node top()
    {
        node tx,ty;
        tx=A.top();
        if(B.size())ty=B.top();
        while(tx.pla==ty.pla && B.size()){A.pop();B.pop();tx=A.top();ty=B.top();}
        return A.top();
    }
}q;
int nxt[110000],las[110000];
int n,m,col[110000];
bool vis[110000];
int main()
{
//  freopen("swap10.in","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&w[i].y),w[i].p=i;
    sort(w+1,w+1+n,cmp);
    int tt=1;col[w[1].p]=1;
    for(int i=2;i<=n;i++)
    {
        if(w[i].y!=w[i-1].y)tt++;
        col[w[i].p]=tt;
    }
    memset(las,-1,sizeof(las));
    for(int i=n;i>=1;i--)
    {
        if(las[col[i]]==-1)nxt[i]=n+1,las[col[i]]=i;
        else nxt[i]=las[col[i]],las[col[i]]=i;
    }
    memset(vis,false,sizeof(vis));
    int ans=0,cnt=0,beg=-1;
    for(int i=1;i<=n;i++)
    {
        if(!vis[col[i]])
        {
            if(cnt==m){beg=i;break;}
            vis[col[i]]=true;
            ans++;cnt++;
            node tmp;tmp.pla=nxt[i];
            q.push(tmp);
        }
        else 
        {
            node tmp;
            tmp.pla=i;q.erase(tmp);
            tmp.pla=nxt[i];q.push(tmp);
        }
        if(cnt==m){beg=i+1;break;}
    }
    if(beg==-1)printf("%d\n",ans);
    else
    {
        for(int i=beg;i<=n;i++)
        {
            if(!vis[col[i]])
            {
                vis[col[i]]=true;ans++;

                node tmp;
                tmp=q.top();
                if(tmp.pla!=n+1)vis[col[tmp.pla]]=false;
                q.pop();
                tmp.pla=nxt[i];
                q.push(tmp);
            }
            else
            {
                node tmp;
                tmp.pla=i;q.erase(tmp);
                tmp.pla=nxt[i];q.push(tmp);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值