zoukankan      html  css  js  c++  java
  • SAM-Toy Cars题解

    题目描述

    Jasio 是一个三岁的小男孩,他最喜欢玩玩具了,他有n 个不同的玩具,它们都被放在了很高的架子上所以Jasio 拿不到它们. 为了让他的房间有足够的空间,在任何时刻地板上都不会有超过k 个玩具. Jasio 在地板上玩玩具. Jasio'的妈妈则在房间里陪他的儿子. 当Jasio 想玩地板上的其他玩具时,他会自己去拿,如果他想玩的玩具在架子上,他的妈妈则会帮他去拿,当她拿玩具的时候,顺便也会将一个地板上的玩具放上架子使得地板上有足够的空间. 他的妈妈很清楚自己的孩子所以他能够预料到Jasio 想玩些什么玩具. 所以她想尽量的使自己去架子上拿玩具的次数尽量的少,应该怎么安排放玩具的顺序呢?

    输入输出格式

    输入格式:

    第一 行三 个整数:n,k,p(1≤k≤n≤100,000,1≤p≤500000), 分别表示玩具的总数,地板上玩具的最多个数以及 JasioJasio 他想玩玩具的序列的个数,接下来 pp 行每行描述一个玩具编号表示 Jasio 想玩的玩具。

    输出格式:

    一个数表示 JasioJasio 的妈妈最少要拿多少次玩具。

    输入输出样例

    输入样例#1: 

    3 2 7
    1
    2
    3
    1
    3
    1
    2

    输出样例#1: 

    4

    思路

    luogu一直AC不了的小朋友们看这里:

    不要提交SP688,提交P3419 [POI2005]SAM-Toy Cars

    不要提交SP688,提交P3419 [POI2005]SAM-Toy Cars

    不要提交SP688,提交P3419 [POI2005]SAM-Toy Cars

    至于为什么,我也不知道。。。反正本人卡了3次提交在luogu上(手动滑稽)

    这道题使用贪心+堆优化。

    贪心为:

    每一次输入一个数将弹出一个大小为k的集合中的一个数才能使该数加入。

    当然,如果该数早就在集合当中就可以直接切换到下一个数。

    前k个数也可以直接进入集合中。

    问题来了?到底弹集合中的哪一个数才能最优呢?

    当然是下一次出现的距离最远的那一个数了。

    堆优化:

    priority_queue<int> q;

    就是一个大根堆。

    那么这道题需要将堆里的类型修改一下。

    priority_queue<pair<int,int> >q;

    pair的前一个储存节点的下一次出现位置,第二个储存该节点的值。

    这样就可以自动的排序出距离最远的那一个数了。

    所以每次操作只需要将q.top()取出,然后将头元素删除——q.pop()。

    最后,上代码:

    #include<algorithm>
    #include<bitset>
    #include<complex>
    #include<deque>
    #include<exception>
    #include<fstream>
    #include<functional>
    #include<iomanip>
    #include<ios>
    #include<iosfwd>
    #include<iostream>
    #include<istream>
    #include<iterator>
    #include<limits>
    #include<list>
    #include<locale>
    #include<map>
    #include<memory>
    #include<new>
    #include<numeric>
    #include<ostream>
    #include<queue>
    #include<set>
    #include<sstream>
    #include<stack>
    #include<stdexcept>
    #include<streambuf>
    #include<string>
    #include<typeinfo>
    #include<utility>
    #include<valarray>
    #include<vector>
    #include<cstring>
    #include<cmath>
    #define ll long long 
    #define FHAKIOI int
    using namespace std;//头文件结束
    inline ll read(){
        ll ret=0,f=1;char ch=getchar();
        while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();}
        while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
        return ret*f;
    }//读优结束
    inline void write(ll zx){
        if(zx<0){zx=-zx;putchar('-');}
        if(zx<10) putchar(zx+'0');
        else{
            write(zx/10);
            putchar(zx%10+'0');
        }
    }//输优结束
    ll n,k,p,a[500010];
    ll use[100010];
    ll f[500010];
    ll las[500010],ans;
    ll nxt[500010];
    priority_queue<pair<int,int> > q;//
    FHAKIOI main(){
        n=read();k=read();p=read();
        for(ll i=1;i<=p;i++) a[i]=read(),las[a[i]]=p+1;//读入
        for(ll i=p;i>=1;i--){
            nxt[i]=las[a[i]];
            las[a[i]]=i;
        }//先预处理与下一次出现的位置的距离
        for(int i=1;i<=p;i++){
            if(use[a[i]]!=0){
                q.push(make_pair(nxt[i],a[i]));//已经在集合里了
            }else if(k!=0){//前K个数
                k--;
                ans++;
                use[a[i]]=1;
                q.push(make_pair(nxt[i],a[i]));
            }else{//最后一种情况,需要弹出一个数
                while(!use[q.top().second]) q.pop();//目前没有在集合中
                int x=q.top().second;//取距离最远的
                q.pop();
                use[x]=0;
                ans++;//ans加一
                use[a[i]]=1;
                q.push(make_pair(nxt[i],a[i]));
            }
        }
        write(ans);putchar('
    ');/输出
        return 0;
    }
  • 相关阅读:
    JUC 1
    给定一个随机数生成器randm(),获得randn()
    堆与优先队列
    集合与映射
    二分搜索树
    链表
    栈与队列
    PostgreSQL ALTER TABLE 命令
    postgresql修改自增序列
    SQL 删除重复行,只保留一条记录
  • 原文地址:https://www.cnblogs.com/yzx1798106406/p/9739955.html
Copyright © 2011-2022 走看看