2019牛客多校赛第十场F.Popping Balloons(multiset+贪心)

4 篇文章 0 订阅
1 篇文章 0 订阅

更多多校信息←请点击这里

F.Popping Balloons

传送门
Recently, an interesting balloon-popping game can be commonly found near the streets. The rule of this game is quite simple: some balloons are tied to cells of a lattice, and you are allowed to throw some darts to prick the balloons. The more balloons you pierce, the more incredible prize you will get.
Probably because too many people have got bored with this childish game, a new variation of the game has appeared. In this variation, you should prick the balloons by shooting an air rifle instead of throwing darts. You can make six shots in total, three horizontally and three vertically. If you shoot horizontally (vertically, resp.), all balloons in the row (column, resp.) are popped. In order to increase the difficulty, there is one restriction imposed on your shots: the distances between any two adjacent horizontal shots and any two adjacent vertical shots must all equal to a given number r r r. The problem is, what is the maximum number of balloons you can pop by making three horizontal and three vertical shots, under the aforementioned restriction.
输入描述:
The first line of input is two integers n, r ( 1 ≤ n , r ≤ 1 0 5 ) 1 \leq n, r \leq 10^5) 1n,r105), the number of balloons and the distance between any two adjacent horizontal or vertical shots.

The remaining part of the input is n lines, specifying the positions of the balloons. Each of these lines contains two integers x, y ( 0 ≤ x , y ≤ 1 0 5 ) (0 \leq x, y \leq 10^5) (0x,y105), denoting a balloon positioned at (x, y). Note that multiple balloons may lie in the same position.
输出描述:
Output the answer as a single integer in one line.
输入
7 1
0 0
1 1
2 2
3 3
4 4
5 5
7 8
输出
6
输入
5 2
0 10
2 3
5 7
9 6
2 3
输出
4


题目大意:
空间中有n个气球,你可以横着社三发子弹,竖着射三发子弹,(打中一排)且横着子弹的关系是y,y+r,y+2*r(每行间隔为r),竖着是x,x+r,x+2*r。(每列间隔为r)问你怎么射才能射爆最多的气球。


题目思路:
首先我们很容易想到遍历行然后找竖的最大收获。那么我们要怎么去O(1)找到最大的竖收获呢,同时行的会对竖的有影响。

我们先将以i为中间的可以收获的y值存进数组二维里。这个数组第二维的大小就是以这行为中间列的气球个数。如h[ i ][ j ]存的就是以i为中间行第j个气球。(这个气球可能在第i-r,i,i+r行中,存这个是方便等会取消对列的影响)

我们再用个数组来存以i为中间列可以获得的气球数量。然后丢进multiset排序。这时候我们就能很快的找到以哪一行为中间列时候获得最多的气球。(即最后一个)
这时候我们只需枚举行,将它们影响到 的列(共三列)的multiset中的值更新,然后更新multiset内的元素。中间一枪打第x行的最大收益即h[x].size()+(当前multiset内最大元素(最后一个元素))。最后再更新回来。


AC_code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=6e5+5;
const int N=6e5+3;

int a[maxn],b[maxn];
int cnt[maxn];//计算中间打在第i列,能射中气球的个数
int ans,n,r;
vector<int>h[maxn];
multiset<int>s; //可存在重复的set
void add(int x){ 
    auto p=s.find(cnt[x]);
    s.erase(p); cnt[x]++;
    s.insert(cnt[x]);
}
void del(int x){
    auto p=s.find(cnt[x]);
    s.erase(p); cnt[x]--;
    s.insert(cnt[x]);
}
int main(){
    cin>>n>>r;
    for (int i=0;i<n;i++){
        cin>>a[i]>>b[i]; 
        a[i]+=r*2;b[i]+=r*2; //把图扩大,向上移2*r
    }
    for (int i=0;i<n;i++){
        h[a[i]-r].push_back(b[i]);  //以a[i]-r该行为中心可以获得1个
        h[a[i]].push_back(b[i]);    //以a[i]该行为中心可以获得1个
        h[a[i]+r].push_back(b[i]);  //以a[i]+r该行为中心可以获得1个
        cnt[b[i]]++; cnt[b[i]-r]++; cnt[b[i]+r]++; //cnt(i)表示中间一枪打第i列,能射中的气球个数。
    }
    for (int i=r;i<=N-r;i++) s.insert(cnt[i]); //计算中间打在第i列,能射中气球的个数
    for (int i=r;i<=N-r;i++){ //以i为中间行
        int ret=(int)h[i].size();
        for (auto x:h[i]) del(x),del(x-r),del(x+r); //如果那一点有气球,先删除掉
        auto p=s.rbegin(); //最后一个元素,也是最大的
        //中间一枪打第x行的最大收益即f(x)+(当前multiset内最大元素)。
        ans=max(ans,ret+(*p));  //比较大小
        for (auto x:h[i]) add(x),add(x-r),add(x+r); //如果那一点有气球,重新加上
    }
    cout<<ans<<endl;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值