>传送门<

前言


跟学知识一样,做题目的确是也是常做常新。这道题当时的确已经解决了,国庆前工作室学长还有其他人又提起这道题,我说不就暴力枚举贪心么,后来学长说那你不好证明贪心的正确性!我一想的确是这样的,基本上没有人讲这怎么三次贪心选取就可以了,有点像瞎搞的样子。于是就又去看了$multiset$的做法,其实用线段树也可以,作用都是较快的维护最大值,只要思维到位了,选择恰当的数据结构就能做出来。

题意


现在给你n个点 ,让你横着划三条线间距为r 然后竖着划三条线间距同样为r ,求经过最多的点数

思路


比赛看到这题的时候觉得能做,但是一看时间限制是5s,搞得我有不敢去碰了,就没有写,但是赛后再看其实并没有那么复杂。有的人是用线段树去写的,感觉线段树简直万能~其实直接求也是可以的,感觉有点暴力(就算是暴力我也想不到QAQ)

下面介绍两者做法,一种是贪心枚举瞎搞,一种是用$multiset+$思维。

贪心枚举(为什么说他瞎搞,这么做感觉是对的,也的确能做,但是你很难证明贪心的正确性,不过在比赛的时候也不失为一种好方法)

正常思路肯定时枚举横的三线和竖的三线,找到最大,这样时O(n2)的复杂度。

一般二维的题目我们枚举一维,比如枚举横三线,

预处理竖三线,以每个x为三线的左线,求出三线包含的气球个数(cntX[i] + cntX[i + r] + cntX[i + r * 2],对竖三线包含的气球数进行从大到小排序,贪心进行选取

然后枚举纵坐标,算出以当前纵坐标为底线的三横线包含的气球个数,由于这样会重复,所以对于横三线已经选取的点竖三线就不再进行选取,之后取最大值和竖三线的值相加就行。

最后,按照这种贪心的取法就能得到最大值(对竖三线的值贪心三次就能得到,这是我没想到的,100会更保险一点)

Code

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + ;
int n, r, cntX[maxn*], cntY[maxn*], res;
struct Point {
int x, y;
bool operator<(const Point &rhs)const {
return x > rhs.x;
}
} a[maxn], sum[maxn]; int main()
{
scanf("%d%d", &n, &r);
for (int i = ; i < n; i++) {
scanf("%d%d", &a[i].x, &a[i].y);
cntX[a[i].x]++;
}
for (int i = ; i < maxn; i++) {
sum[i].x = cntX[i] + cntX[i + r] + cntX[i + r * ];
sum[i].y = i;
}
sort(sum, sum + maxn);
for (int i = ; i < ; i++) {
memset(cntY, , sizeof(cntY));
for (int j = ; j < n; j++)
if (a[j].x != sum[i].y && a[j].x != sum[i].y + r && a[j].x != sum[i].y + r * )
cntY[a[j].y]++;
int my = ;
for (int j = ; j < maxn; j++)
my = max(my, cntY[j] + cntY[j + r] + cntY[j + r * ]);
res = max(res, my + sum[i].x);
}
printf("%d\n", res);
return ;
}
/*
总体的思路就是分别对横纵坐标暴力枚举三条线经过的点数(去重),然后通过贪心的思想选取,最后出来的就是最大值
首先直接用sum[i].x枚举三条竖线(i, i+r, i+2*r)能够经过的点数,sum[i].y记录当前枚举是从横坐标为i这条竖线开始的
然后对sum[i]按x从大到小排序,贪心的选取sum[i]后,肯定不能直接枚举三条横线能够经过的点数,因为这样会有重复。
那怎么办呢?我们就先对cntY[a[j].y]进行处理,假如我选取的sum[i]中已经包含a[j]这个点了,那么我的cntY[[a[j].y]就不能加1,因为这个点已经被计算过
现在当然就可以枚举三条横线能够经过的点数,取最大值和sum[i].x相加就是当前总共能经过的最多点数
*/

 

$multiset+$思维

官方题解说的已经很详细了,这种题其实很考验思维。

我们用$f(i)$表示中间一枪打第$i$行,能够射中的气球个数,用$g(i)$表示中间一枪打第$i$列,能射中的气球个数。

用$multiset$存所有$f(i)$的值,枚举中间一枪打第$x$列,将对每一个位于第$x-r,x+r$列的气球,将它们影响到的行(共三行)的$f(j)$的值更新,然后更新$multiset$内的元素。

中间一枪打第$x$列的最大收益即$g(x)$+(当前$multiset$内最大元素)。

Code

#include<cstring>
#include<string>
#include<set>
#include<vector>
using namespace std;
const int maxn = 1e5 + ;
const int M = 1e5; int cnt[maxn];
vector <int> h[maxn];
multiset<int> s;
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]);
}
//multiset + 思维
int main()
{
int n, r, x, y, ans = ;
scanf("%d%d", &n, &r);
for (int i = ; i < n; i++) {
scanf("%d%d", &x, &y);
h[x].push_back(y);
if (x - r >= ) h[x - r].push_back(y);
if (x + r <= M) h[x + r].push_back(y);
cnt[y]++;
if (y - r >= ) cnt[y - r]++;
if (y + r <= M) cnt[y + r]++;
}
for (int i = ; i <= M; i++) s.insert(cnt[i]);//往multiset里添加行的气球数
for (int i = ; i <= M; i++) {
int res = (int)h[i].size();//三列的气球总数
for (int j = ; j < res ; j++) {//如果影响了三行,就更新
del(h[i][j]);
if (h[i][j] - r >= ) del(h[i][j] - r);
if (h[i][j] + r <= M) del(h[i][j] + r);
}
ans = max(ans, res + (int)(*s.rbegin()));//取最大值
for (int j = ; j < res ; j++) {//再更新回去
add(h[i][j]);
if (h[i][j] - r >= ) add(h[i][j] - r);
if (h[i][j] + r <= M) add(h[i][j] + r);
}
}
printf("%d\n", ans);
return ;
}

2019牛客暑期多校训练营(第十场)F-Popping Balloons的更多相关文章

  1. 2019牛客暑期多校训练营(第三场)- F Planting Trees

    题目链接:https://ac.nowcoder.com/acm/contest/883/F 题意:给定n×n的矩阵,求最大子矩阵使得子矩阵中最大值和最小值的差值<=M. 思路:先看数据大小,注 ...

  2. 2019牛客暑期多校训练营(第三场) F.Planting Trees(单调队列)

    题意:给你一个n*n的高度矩阵 要你找到里面最大的矩阵且最大的高度差不能超过m 思路:我们首先枚举上下右边界,然后我们可以用单调队列维护一个最左的边界 然后计算最大值 时间复杂度为O(n*n*n) # ...

  3. 2019牛客暑期多校训练营(第九场)A:Power of Fibonacci(斐波拉契幂次和)

    题意:求Σfi^m%p. zoj上p是1e9+7,牛客是1e9:  对于这两个,分别有不同的做法. 前者利用公式,公式里面有sqrt(5),我们只需要二次剩余求即可.     后者mod=1e9,5才 ...

  4. 2019牛客暑期多校训练营(第一场)A题【单调栈】(补题)

    链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 题目描述 Two arrays u and v each with m distinct elem ...

  5. 2019牛客暑期多校训练营(第一场) B Integration (数学)

    链接:https://ac.nowcoder.com/acm/contest/881/B 来源:牛客网 Integration 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 5242 ...

  6. 2019牛客暑期多校训练营(第一场) A Equivalent Prefixes ( st 表 + 二分+分治)

    链接:https://ac.nowcoder.com/acm/contest/881/A 来源:牛客网 Equivalent Prefixes 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/ ...

  7. 2019牛客暑期多校训练营(第二场)F.Partition problem

    链接:https://ac.nowcoder.com/acm/contest/882/F来源:牛客网 Given 2N people, you need to assign each of them ...

  8. 2019牛客暑期多校训练营(第一场)A Equivalent Prefixes(单调栈/二分+分治)

    链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 Two arrays u and v each with m distinct elements ...

  9. [状态压缩,折半搜索] 2019牛客暑期多校训练营(第九场)Knapsack Cryptosystem

    链接:https://ac.nowcoder.com/acm/contest/889/D来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言52428 ...

  10. 2019牛客暑期多校训练营(第二场)J-Subarray(思维)

    >传送门< 前言 这题我前前后后看了三遍,每次都是把网上相关的博客和通过代码认真看了再思考,然并卵,最后终于第三遍也就是现在终于看懂了,其实懂了之后发现其实没有那么难,但是的的确确需要思维 ...

随机推荐

  1. MyBatis 接口多参数的处理方法

    From<MyBatis从入门到精通> 1.接口类中增加的方法: /* 2.7 多个接口参数的用法 多个参数时,可以选取的方案有:使用Map类型或者使用@Param注解 使用Map类型作为 ...

  2. 快速掌握mongoDB(四)—— C#驱动MongoDB用法演示

    前边我们已经使用mongo shell进行增删查改和聚合操作,这一篇简单介绍如何使用C#驱动MongoDB.C#驱动MongoDB的本质是将C#的操作代码转换为mongo shell,驱动的API也比 ...

  3. 浅谈MQTT

    一.什么是MQTT MQTT的全称是“ Message Queuing Telemetry Transport”,即消息队列遥测传输,是一种基于订阅/发布模式的应用层协议,而http是一种基于rest ...

  4. mac 部署安装接口自动化持续集成 jmeter+ant+jenkins

    由于前段时间刚换的工作,公司用的是mac电脑办公,之前办公都是windows系统.刚开始使用时连基本的操作都要去找度娘,很不习惯,新电脑开始就是安装相关的工作工具 下面就说说遇到的哪些坑. 1.  m ...

  5. dij模板

    #include<cstdio> #include<vector> #include<queue> using namespace std; struct edge ...

  6. python 文件读写总结

    这是个人在项目中抽取的代码,自己写的utils的通用模块,使用的框架是tronado,包括了文件的读写操作,api格式的统一函数,如有特别需要可以联系我或者自己扩展,刚学python不久,仅供参考,例 ...

  7. HTTP_5_通信数据转发程序:代理、网关、隧道

    HTTP通信时,除客户端和服务器之外,还有一些用于通信数据转发的应用程序,例如代理,网关,隧道.配合服务器工作. 代理 转发功能,客户端与服务器之间可有多个代理, 缓存代理:减少服务器压力,透明代理: ...

  8. Windows 使用 helm3 和 kubectl

    简介: 主要原因是,我不会 vim ,在 linux 上修改 charts 的很蹩脚,所以就想着能不能再 windows 上执行 helm 命令,将 charts install linux 上搭建的 ...

  9. 2. Java基本数据类型及运算符

    1. 计算机数制 1.1 计算机信息单位 阅读二进制.字节.字长,回答以下问题: 1. 计算机中采用什么进制存储信息,它的优点是什么 2. 什么是位.字节 3. K.M.G.T.P之间的转换 4. 什 ...

  10. 原创:用node.js搭建本地服务模拟接口访问实现数据模拟

    前端开发中,数据模拟是必要的,这样就能等后台接口写完,我们直接把接口请求的url地址从本地数据模拟url换成后台真实地址就完成项目了.传参之类的都不用动. 之前网上找了很多类似于mock等感觉都不太实 ...