刷题记录(NC235267 星球大战,NC216012 Let‘s Play Curling,NC235294 任务,NC235569 牛可乐与NCPC)

NC235267 星球大战

题目链接

关键点:

1、用一个map来记每行(mx)的敌人(列数),再用一个map来记每列(my)的敌人(行数),map值为一个multiset因为数据可能重复。

2、每当攻击一行时,对于消灭的人数即为记行的map的键值为d的size(mx[d].size()),然后遍历该mx[d],将所有的出现的列(比如为x)都在my中删除(my[x].erase(d)),然后再清除mx[d].clear()

攻击一列也类似

完整代码:

# include <cstdio>
# include <iostream>
# include <map>
# include <set>
using namespace std;
int n, m;
map<int, multiset<int>>mx;//记录某行上的战舰
map<int, multiset<int>>my;;//记录某列上的战舰
int main()
{
    cin>>n>>m;
    for (int i=1; i<=n; i++)
    {
        int x, y;
        cin>>x>>y;
        mx[x].insert(y);
        my[y].insert(x);
    }
    for (int i=1; i<=m; i++)
    {
        int c, d, ans;
        cin>>c>>d;
        if (c==0)
        {
            ans = mx[d].size();
            multiset<int>::iterator it;
            for (it = mx[d].begin(); it!=mx[d].end(); it++)
                my[*it].erase(d);
            mx[d].clear();
        }
        else
        {
            ans = my[d].size();
            multiset<int>::iterator it;
            for (it = my[d].begin(); it!=my[d].end(); it++)
                mx[*it].erase(d);
            my[d].clear();
        }
        cout<<ans<<endl;
    }
    
    
    return 0;
}

NC216012 Let‘s Play Curling

题目链接

关键点:

1、题目要求即为求连续红球的最多个数,可以通过多次画图得出

2、用一个map来标记该球为红还是蓝,然后求红球的前缀和,如果红球中出现了篮球,那么当前前缀和直接清零,每次更新最大值

完整代码

# include <bits/stdc++.h>
using namespace std;
int t;
map<int, int>mp;
map<int, int>cnt;
int main()
{
    cin>>t;
    while (t--)
    {
        int n, m;
        mp.clear();
        cnt.clear();
        cin>>n>>m;
        for (int i=1; i<=n; i++)
        {
            int x;
            cin>>x;
            mp[x] = 1;
            cnt[x]++;
        }
        for (int i=1; i<=m; i++)
        {
            int y;
            cin>>y;
            mp[y] = 2;
            cnt[y]=0;
        }
        int tmp = 0, ans = 0;
        for (auto &it : mp)
        {
            if (it.second == 2) tmp = 0;
            else tmp += cnt[it.first];
            ans = max(ans, tmp);
        }
        if (ans)
            cout<<ans<<endl;
        else
            cout<<"Impossible"<<endl;
    }
    
    
    return 0;
}

NC235294 任务

题目链接

关键点

1、首先如何完成最多的任务,按时间为第一关键字,等级为第二关键字来从大到小排序,对于每一次的任务,我们找出可以完成的机器就去完成,不要管后面的任务(肯定也能完成),反正都是完成一次

2、接下来为求最大的报酬

(500∗xi​+2∗yi​)元报酬。
xi(0<xi≤1440)

yi​(0≤yi​≤10)

因此就算对于 yi取最大也不如x相差1,因此按照该方式排序是有道理的

3、接下来对于一个任务可能有多个机器都可以完成,那么我们就贪心的选择y刚刚好可以完成的机器

4、因为y值可能相等,但又为不同的机器,因此我们可以用multiset来存对于该任务可以完成的机器,然后用lower_bound来求刚刚好可以完成ylevel的机器

# include <bits/stdc++.h>
using namespace std;
const int N = 100000+10;
long long n, m, maxnum, maxpay;
multiset<int>se;
struct machine{
    int time;
    int level;
}ma[N];
struct task{
    int time;
    int level;
}ta[N];
bool cmp1(machine m1, machine m2)
{
    if (m1.time!=m2.time)
        return m1.time>m2.time;
    else
        return m1.level>m2.level;
}
bool cmp2(task t1, task t2)
{
    if (t1.time!=t2.time)
        return t1.time>t2.time;
    else
        return t1.level>t2.level;
}
int main()
{
    cin>>n>>m;
    for (int i=1; i<=n; i++)
    {
        cin>>ma[i].time>>ma[i].level;
    }
    for (int i=1; i<=m; i++)
    {
        cin>>ta[i].time>>ta[i].level;
    }
    sort(ma+1, ma+1+n, cmp1);
    sort(ta+1, ta+1+m, cmp2);
    int pos = 1;
    for (int i=1; i<=m; i++)
    {
        while (pos<=n && ma[pos].time>=ta[i].time)
        {
            se.insert(ma[pos].level);
            pos++;
        }
        auto it = se.lower_bound(ta[i].level);
        if (it!=se.end())
        {
            maxnum++;
            maxpay = maxpay+500*ta[i].time+2*ta[i].level;
            se.erase(it);
        }
    }
    cout<<maxnum<<" "<<maxpay<<endl;
    
    
    return 0;
}

NC235569 牛可乐与NCPC

题目链接

关键点:

1、题目要求即为求每次肚子里没有点的点的个数

2、因为点可能相同,但又为不同点,所以用一个multiset来存点(可以进入队伍的点),然后按照x,y从小到大排序,我们可以发现对于一个不能进入队伍的点,说明其有其他点在肚子里,以后无论再继续插入什么点,都无法改变其进入不了队伍的事实,因此每次判断下一个点时,只要判断其与进入队伍的点的关系就行

3、对于每一次插入的点,我们先看该点是否能进入队伍,我们从multiset中lower_bound(),然后减一,找到比该点的x小的点,再看找到的点的y如果比该点大,那么该点就可以进入队伍(x,y从小到大排序)

4、最后再清除因为该点加入而导致队伍里的其他点退出的点

完整代码

# include<bits/stdc++.h>
using namespace std;
int t;
struct ty{
    int x, y;
    bool operator < (const ty& a) const
    {
        if (x!=a.x)
            return x<a.x;
        else
            return y<a.y;
    }
}p;
multiset<ty>m;
int main()
{
    cin>>t;
    int cnt = 1;
    while (t--)
    {
        printf("Case #%d:\n", cnt++);
        int n;
        cin>>n;
        m.clear();
        for (int i=1; i<=n; i++)
        {
            int x, y;
            cin>>x>>y;
            p.x = x;
            p.y = y;
            auto it = m.lower_bound(p);
            if (it==m.begin() || (--it)->y>y)
            {
                m.insert(p);
                auto it = m.upper_bound(p);
                while (it!=m.end() && it->y>y) 
                    m.erase(it++);
            }
            cout<<m.size()<<endl;
        }
        cout<<endl;
    }
    
    
    
    return 0;
}

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值