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;
}