hdu 3673 David Shopping

来源:互联网 发布:单片机 8位可变波特率 编辑:程序博客网 时间:2024/05/01 10:39

题目大意比较长,我几句话说不出来。

下面是摘的别人的题目大意:

你有一个能放M(M <= 50000)个物品的容器,你可能会遇到N(N <= 100000)个物品。
    规则:
        1.遇到的物品K你如果之前没有遇到过,且你的容器未满,那么把这个物品(编号K),放进容器中,并记录数字1(相当于权值),且记录遇到该物品的时间t。
        2.遇到的物品K如果在你的容器里,那么仅仅把它的标记数字(即所谓权值+1)。
        3.遇到的物品K你如果之前没有遇到过,且你的容器已满,那么就把容器里标记数字最大的容器移除,如果不止一个,那么就把最先进入容器的那一个移除。(移除的物品就相当于没有遇到过,之后遇到算第一次遇到。)
    求解问题:给你M,N,以及一行数字N个K(i),(K(i)< 2^20,i = 1 to N),输出共发生移除操作多少次。(TimeLimit:1s) 

题解:

此题目是一个模拟题,关键在于找到高效的模拟方法。

最方便的是用set+重载set的比较函数,使得set中的排序是先按照l[i]排序,l[i]==l[j]时再按照装入背包的时间排序。(可以看作是一个可修改堆)

用set时有一些需要注意的地方,见程序。

#include<iostream>#include<set>#include<cstdio>#include<cstring>using namespace std;int n,ans;unsigned int m;int l[2000000];//原题目中的lint t[2000000];//物品x装入背包的最早时间int a[200000];struct cmp//重载比较函数{    bool operator()(int x,int y)const    {    if(l[x]<l[y])return true;    else if(l[x]==l[y]&&t[x]>t[y]) return true;    return false;    }};set<int,cmp> myset;set<int,cmp>::reverse_iterator it;int main(){    int sec=0;    while(scanf("%u%d",&m,&n),m||n)    {        sec++;ans=0;        myset.clear();        memset(l,0,sizeof(l));        for(int i=1;i<=n;i++)        scanf("%d",&a[i]);        for(int i=1;i<=n;i++)        {            if(myset.count(a[i])==0)            {                if(myset.size()<m)                {                    l[a[i]]=1;t[a[i]]=i;myset.insert(a[i]);                }                else                {                    ans++;                    it=myset.rbegin();                    myset.erase(*it);                    l[a[i]]=1;t[a[i]]=i;myset.insert(a[i]);                }            }            else            {//注意l[a[i]]发生变化后要先删除原来的a[i],再插入a[i]。(否则会打乱顺序)                myset.erase(a[i]);                l[a[i]]++;                myset.insert(a[i]);            }        }        printf("Case %d: %d\n",sec,ans);    }    return 0;}


原创粉丝点击