刷题记录(NC20185 [JSOI2010]缓存交换,NC50439 tokitsukaze and Soldier,NC20154 [JSOI2007]建筑抢修)

NC20185 [JSOI2010]缓存交换

题目链接

关键点: 

1、当前容量够用时就直接存入,当不够时,将之后要最晚用到的先排出

2、我们用一个nexti数组来存每个位置元素下一次出现的位置,如果没出现就为最大值。先从后往前来遍历,用一个map数组来记当前位置的字母位置。

3、接着用一个大顶堆(q)来记存入缓存区里的每个数字最后一次出现的位置, 这样就可以直接top取值,top掉。用一个vis数组来存当前存入缓存区的位置

4、如果当前元素缓存区中没有,但是缓存区有空间,那么就vis就记上当前位置的字母的下一个位置(相同字母),q就push进去当前的下一个位置,如果没有空间,拿出q的top将其弹出,vis的该位置也改为0, 并将该位置的下一个位置存入vis,如果当前元素存在缓存区,那么就在vis中记下当前位置的下一个位置,并且push进去堆中

完整代码

# include<bits/stdc++.h>
using namespace std;
const int N = 100000+10;
int n, m;
int nexti[N];
int vis[N];
int a[N];
map<int, int>mp;
int ans, total;
priority_queue<int>q;
int main()
{
    cin>>n>>m;
    for (int i=1; i<=n; i++)
    {
        int x;
        cin>>x;
        a[i] = x;
    }
    for (int i=n; i>=1; i--)
    {
        if (!mp[a[i]]) nexti[i] = N;
        else 
            nexti[i] = mp[a[i]];
        mp[a[i]] = i;
    }
    for (int i=1; i<=n; i++)
    {
        if (!vis[i])
        {
            ans++;
            if (total<m)
            {
                total++;
                vis[nexti[i]] = 1;
                q.push(nexti[i]);
            }
            else
            {
                vis[q.top()] = 0;
                q.pop();
                vis[nexti[i]] = 1;
                q.push(nexti[i]);
            }
        }
        else
        {
            vis[nexti[i]] = 1;
            q.push(nexti[i]);
        }
    }
    cout<<ans;
    
    return 0;
}

NC50439 tokitsukaze and Soldier

题目链接

关键点

1、将士兵的要求人数从大到小排序,然后开始遍历,用一个小顶堆来存当前加入战队的每个士兵的战力,如果当前士兵的要求人数大于等于小堆那么直接存入,如果小于顶堆,顶堆排出元素,减去战力,并且加上当前士兵的战力,每次按该策略,更新最大战力

完整代码

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000+10;
ll maxx;
struct ty{
    int s, v;
}t[N];
priority_queue<int, vector<int>, greater<int> >q;
bool cmp(ty t1, ty t2)
{
    return t1.s>t2.s;
}
ll n, ans;
int main()
{
    cin>>n;
    for (int i=1; i<=n; i++)
        cin>>t[i].v>>t[i].s;
    sort(t+1, t+1+n, cmp);
    ll res = 0;
    for (int i=1; i<=n; i++)
    {
        q.push(t[i].v);
        res += t[i].v;
        while (!q.empty() && q.size()>t[i].s)
        {
            res -= q.top();
            q.pop();
        }
        ans = max(ans, res);
    }
    cout<<ans<<endl;
    
    return 0;
}

NC20154 [JSOI2007]建筑抢修

题目链接

关键点:

1、一样的,将所有建筑按照deadline从小到大排序,并用一个大顶堆(q)来存想要建造的建筑的工作时间,开始遍历,每次算出完工时间,一旦完工时间大于当前建筑的deadline,就将q中完工时间大的弹出,直到可以完成,再将其push,每次求最多的修建建筑(q.size())

完整代码

# include <iostream>
# include <cstdio>
# include <queue>
# include <algorithm>
using namespace std;
const int N = 150000+10;
typedef long long ll;
int n;
priority_queue<ll>q;
struct ty{
    ll t1, t2;
}t[N];
bool cmp(ty t1, ty t2)
{
    return t1.t2<t2.t2;
}
int main()
{
    cin>>n;
    for (int i=1; i<=n; i++)
        cin>>t[i].t1>>t[i].t2;
    sort(t+1, t+1+n, cmp);
    int ans = 0, totalt = 0;
    for (int i=1; i<=n; i++)
    {
        totalt += t[i].t1;
        q.push(t[i].t1);
        while (!q.empty() && totalt>t[i].t2)
        {
            totalt -= q.top();
            q.pop();
        }
        if (ans<q.size() && !q.empty())
        ans = q.size();
    }
    cout<<ans<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值