2 条题解

  • 18
    @ 2023-8-22 15:59:41

    按照管理员的思路自己写了一个,开启O2优化后大概在850ms,看了一下提交记录属于中档水平,满意了

    #include <iostream>
    #include <queue>
    using namespace std;
    queue<pair<int,int>> b;
    bool on_floor[100005];
    struct cmp{
        bool operator()(pair<int,int> x,pair<int,int> y)
        {
            return x.second<y.second;
        }
    };
    priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> floor;
    int main()
    {
        int n,k,p,ans=0,floor_size=0;
        cin>>n>>k>>p;
        queue<int> temp1;
        queue<int> temp2[100005];
        for(int i=1;i<=p;i++)
        {
            int x;
            cin>>x;
            temp1.push(x);
            temp2[x].push(i);
        }
        for(int i=1;i<=n;i++)
            temp2[i].pop();
        for(int i=1;i<=p;i++)
        {
            if(temp2[temp1.front()].size()==0)
                b.push(make_pair(temp1.front(),p+1));
            else
            {
                b.push(make_pair(temp1.front(), temp2[temp1.front()].front()));
                temp2[temp1.front()].pop();
            }
            temp1.pop();
        }
        for(int i=1;i<=p;i++)
        {
            if(!on_floor[b.front().first])
            {
                if(floor_size==k)
                {
                    while(!on_floor[floor.top().first])
                        floor.pop();
                    on_floor[floor.top().first]=false;
                }
                else
                    floor_size++;
                floor.push(b.front());
                on_floor[b.front().first]=true;
                ans++;
            }
            else
            {
                floor.push(b.front());
            }
            b.pop();
        }
        cout<<ans;
    }
    
  • 15
    @ 2023-7-6 16:26:41

    被放回架子的玩具,在下次想玩时,一定需要重新从架子上拿下来,而这件事越晚发生越有利,因此可以采用这样的贪心策略:每次需要把玩具放回架子时,都选择下次被需要的时间最晚的玩具。(以后不再需要的,可以把下次被需要的时间设为一个大于10000的数)

    a[i]表示第i个被需要的玩具,nxt[i]表示它下次被需要的时间。在求nxt数组的时候,可以倒序循环,用pos[x]表示x号玩具下次出现的时间,每次把nxt[i]赋值为pos[a[i]]即可。

    维护一个优先队列,存放当前在地上的每一个玩具下次被需要的时间。每次需要把玩具放回架子时,取出队头元素。

    使用数组inq维护每个玩具当前是否在地上,如果当前被需要的玩具在地上,那么就不需要取出队头。此时需要注意更新这件玩具下次被需要的时间,可以直接把新的时间加入队列。但是这样会导致队列里存在多个时间对应同一件玩具,对于这种情况,可以在把新的时间加入队列的时候,让k加1,以容纳多余的时间。而在取出队头的时候,通过inq检查它是否在队列里,如果已经不在,说明之前已经让这个玩具放回架子了,忽略这个时间,并让k减1。

    统计把玩具拿到地上的次数即是最终答案。

    核心代码
    
    for (int i = 1; i <= 100000; i++) {//最初把所有玩具下次出现的时间设为大于10000的数
        pos[i] = p + i;
        a[p + i] = i;
    }
    for (int i = p; i >= 1; i--) {//计算nxt数组
        nxt[i] = pos[a[i]];
        pos[a[i]] = i;
    }
    for (int i = 1; i <= p; i++) {
        if (inq[a[i]]) {//如果玩具已经在地上,就更新下次出现的时间,并让k加1
            q.push(nxt[i]);
            k++;
            continue;
        }
        if (q.size() >= k) {//如果地上已经满了,就挑一个放回去
            while (q.size() > 0 && !inq[a[q.top()]]) {//这里是处理一个玩具多次进入队列的情况
                q.pop();
                k--;
            }
            int x = q.top();
            q.pop();
            inq[a[x]] = false;
        }
        q.push(nxt[i]);//把当前需要的玩具拿到地上
        inq[a[i]] = true;
        ans++;
    }
    
    • 1

    信息

    ID
    258
    时间
    1000ms
    内存
    256MiB
    难度
    5
    标签
    (无)
    递交数
    795
    已通过
    324
    上传者