Meetings S 题解
题目描述
有两个牛棚位于一维数轴上的点 \(0\) 和 \(L\) 处。同时有 \(N\) 头奶牛位于数轴上不同的位置(将牛棚和奶牛看作点)。每头奶牛 \(i\) 初始时位于某个位置 \(x_i\),并朝着正向或负向以一个单位每秒的速度移动,用一个等于 \(1\) 或 \(-1\) 的整数 \(d_i\) 表示。每头奶牛还拥有一个在范围 \([1,10^3]\) 内的重量。所有奶牛始终以恒定的速度移动,直到以下事件之一发生:
- 如果奶牛 \(i\) 移动到了一个牛棚,则奶牛 \(i\) 停止移动。
- 当奶牛 \(i\) 和 \(j\) 占据了相同的点的时候,并且这一点不是一个牛棚,则发生了相遇。此时,奶牛 \(i\) 被赋予奶牛 \(j\) 先前的运动方向,反之亦然。注意奶牛可能在一个非整数点相遇。
- 令 \(T\) 等于停止移动的奶牛(由于到达两个牛棚之一)的重量之和至少等于所有奶牛的重量之和的一半的最早时刻。请求出在时刻 \(0 \ldots T\)(包括时刻 \(T\))之间发生的奶牛对相遇的总数。
输入格式
输入的第一行包含两个空格分隔的整数 \(N\) 和 \(L\)。
以下 \(N\) 行,每行包含三个空格分隔的整数 \(w_i\) ,\(x_i\) 以及 \(d_i\) 。所有的位置 \(x_i\) 各不相同,并且满足 \(0<x_i<L\)。
输出格式
输出一行,答案,即在时刻 \(0 \ldots T\)(包括时刻 \(T\))之间发生的奶牛对相遇的总数。
样例输入
3 5
1 1 1
2 2 -1
3 3 -1
样例输出
2
分析
首先,这道题是个二分没跑了
我们二分查找符合的停下时间 \(mid\),然后在算出在这期间有多少牛相遇即可
Part 1 如何写二分中的check函数?
我们先来看几个结论:
(1): 假设两只牛发生相遇事件,\(1\) 为牛的速度,\(W\) 为牛的体重,故一次相遇事件可以表述成下图。
A(1, WA)-------> <--------B(1, WB)
<-------A(1, WA) B(1, WB)-------->
如果我们先不看牛的速度,只看体重,那么:
WA-------> <--------WB
<-------WA WB-------->
所以我们可以看作两只牛相遇后,方向保持不变,但交换了身体。 艺术带师?
(2): 还是(1)的这幅图。
你会发现当两只牛相遇之后,这两只牛的相对位置是没有改变的。也就是说在任何时候整个数轴上从左往右的第 \(i\) 只牛的信息一定是最初输入的 \(C[i]\)。
WA-------> <--------WB
<-------WA WB-------->
(3): 由(1)我们可以把每次的相遇看作不改变牛的方向,但改变了重量。
可以推出当一只牛在 \(a\) 处时,\(T\) 秒后一定会有一只牛在同一方向的 \(a + T\) 处。
又因为(2)而如果我们知道了这头牛是当时整个数轴上的从左往右第几头,那么就一定可以知道这头牛的相关信息
所以很容易写出 \(check\) 函数:
bool check(int t) {
int W = 0; // 到达牛棚的牛的总重量
int s = 1, e = n;
// 根据(2):牛的相对位置不变
// 直接表示出某一头相对位置确定的牛
for(int i = 1; i <= n; i++) { // 根据(3)
if(cow[i].d == 1)
if(cow[i].x + t >= L) { // 如果t分钟后有牛到了右牛棚
W += cow[e].w;
// 此牛一定是目前所在位置最靠右且未到达右牛棚的牛
// 累加总重量
e--;
// 更新目前位置最靠右的牛的位置
}
else {
if(cow[i].x - t <= 0) { // 同
W += cow[s].w;
s++;
}
}
}
return s >= sum;
}
Part 2 如何在知道时间的情况下计算出答案?
很简单嘛,题目要求我们算出在这个时间段内发生了多少次牛的相遇事件。
那么我们就单独看每只向左走的牛,如果能算出与它们每只牛在这个时间段中与多少只向右走的牛相遇,答案也就迎刃而解了(毕竟所有向左走的牛发生的相遇事件的总数就是我们的答案
那么,如何求出可以和它相遇的往右走的最左边的牛呢?
同样使用二分:
int work(int t) { // 答案函数
int len = 0, ans = 0;
for(int i = 1; i <= n; i++) {
if(cow[i].d == -1) { // 枚举每只向左走的牛
int x_ = cow[i].x - t * 2;
int l = 0, r = len + 1;
while(l + 1 < r) { // 找出能与这头向左走的牛相遇的最左边的牛
int mid = (l + r) >> 1;
if(f[mid] >= x_) r = mid;
else l = mid;
}
ans += (len - r + 1);
// r是最左边的牛能与i相遇的牛,而len是目前所有向右走的牛的个数
// 所以len-r+1就是在这一个时间段i牛能与几头向左走的牛相遇
}
else f[++len] = cow[i].x; // 记录每只向右走的牛
}
return ans;
}
我要调疯了。。。
AC代码
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 50005;
struct data { // 牛的信息
int w, x, d;
int id;
// w表示牛的重量,x表示牛的初始位置,d表示牛的行动方向
// id表示牛的初始编号(从左到右
} cow[MAXN], ans[MAXN];
bool cmp(data a, data b) {
return a.x < b.x; // 按初始位置排序
}
int n, L; // 有n头牛,数轴上最右边的牛棚的距离为L
int sum = 0; // 牛的总重量
int f[MAXN];
bool check(int t) {
int W = 0; // 到达牛棚的牛的总重量
int s = 1, e = n;
// 根据(2):牛的相对位置不变
// 直接表示出某一头相对位置确定的牛
for(int i = 1; i <= n; i++) { // 根据(3)
if(cow[i].d == 1) {
if(cow[i].x + t >= L) { // 如果t分钟后有牛到了右牛棚
W += cow[e].w;
// 此牛一定是目前所在位置最靠右且未到达右牛棚的牛
// 累加总重量
e--;
// 更新目前位置最靠右的牛的位置
}
}
else {
if(cow[i].x - t <= 0) { // 同
W += cow[s].w;
s++;
}
}
}
return W * 2 >= sum;
}
int work(int t) { // 答案函数
int len = 0, ans = 0;
for(int i = 1; i <= n; i++) {
if(cow[i].d == -1) { // 枚举每只向左走的牛
int x_ = cow[i].x - t * 2;
int l = 0, r = len + 1;
while(l + 1 < r) { // 找出能与这头向左走的牛相遇的最左边的牛
int mid = (l + r) >> 1;
if(f[mid] >= x_) r = mid;
else l = mid;
}
ans += (len - r + 1);
// r是最左边的牛能与i相遇的牛,而len是目前所有向右走的牛的个数
// 所以len-r+1就是在这一个时间段i牛能与几头向左走的牛相遇
}
else f[++len] = cow[i].x; // 记录每只向右走的牛
}
return ans;
}
int main() {
scanf ("%d %d", &n, &L);
for(int i = 1; i <= n; i++) {
scanf ("%d %d %d", &cow[i].w, &cow[i].x, &cow[i].d);
sum += cow[i].w;
cow[i].id = i;
}
sort(cow + 1, cow + n + 1, cmp);
int l = 0, r = 1e9, t = 0;
// l最小为1
// r最小为L,即开始在数轴上0的牛都已经走到了最右边的牛棚
while(l <= r) { // 二分时间
int mid = (l + r) >> 1;
if(check(mid)) {
r = mid - 1;
t = mid;
}
else l = mid + 1;
}
printf("%d", work(t));
// 算出有多少头牛在此时间内相遇过
return 0;
}
Meetings S 题解的更多相关文章
- QBXT 提高组储备营 2020.夏 游记
DAY 1 是第一天呐!老师好强!讲得好仔细!连我都全懂了![doge] 突然对后面几天充满了期待-- 复习内容:二分,排序,贪心,搜索(好评) 新知识:Huffman树及Huffman编码,对拍,二 ...
- 题解 P5835 【 USACO19DEC Meetings S】
前言 这道题目是道好题,想通了之后就可以把轻松这道题做出来. 正文 结论 先把一个结论写出来. 无论所有奶牛怎么走,它们的体重从左往右组成的序列是不会发生改变的. 这个结论简单地说明一下. 首先我们可 ...
- USACO19DEC题解
Bronze A Cow Gymnastics 题目:https://www.luogu.com.cn/problem/P5831 题解:用数组存一下出现位置,O(n^2)枚举一下就好. 代码: #i ...
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- Codeforces Round #353 (Div. 2) ABCDE 题解 python
Problems # Name A Infinite Sequence standard input/output 1 s, 256 MB x3509 B Restoring P ...
- 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解
题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...
- 2016ACM青岛区域赛题解
A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
随机推荐
- es6 新的数组操作
ES6数组新增的几个方法 2017年03月24日 13:38:04 tang15886395749 阅读数:10461 标签: ES6数组新增方法 更多 个人分类: js相关 关于数组中forEa ...
- Redis---01简述目录结构与redis.conf文件
一.Redis目录结构 (当前Redis是在CentOS 7 1708 64位环境下,Redis版本为3.2.5) 进入默认的Redis安装目录/usr/local/bin,可以看见这些下图目录结构 ...
- oracle基本学习
oracle目录及卸载 1.oracle的目录介绍: oradata:数据库存储文件的目录 db_home: network >admin:配置网络服务和监听器服务 jdk:oracle自带jd ...
- 专题四:redis的数据类型之list
一.基本介绍 对于list,它的存储需求是什么呢?对于string,讲究单个,hash也不讲究大量:当我们需要存储多个数据的时候,前面的数据类型就不大合适了. 数据存储需求:存储多个数据,并对数据进入 ...
- python数据分析使用matplotlib绘图
matplotlib绘图 关注公众号"轻松学编程"了解更多. Series和DataFrame都有一个用于生成各类图表的plot方法.默认情况下,它们所生成的是线形图 %matpl ...
- dhcp、tftp、httpd、pxe安装CentOS6.9
虚拟机网络设置 要xshell连接虚拟机注意设置VMware Network Adapter VMnet2在同一网段 1.利用光盘配置本地yum源 [root@ZYB ~]# mount -r /de ...
- ubuntu18.04下stlink的一种安装方法
安装前准备: 从软件包存储库中安装以下软件包: git gcc或clang或mingw32-gcc或mingw64-gcc(C编译器:很可能已经存在gcc) build-essential (在基于D ...
- MySQL全面瓦解10:分组查询和聚合函数
概述 相信我们经常会遇到这样的场景:想要了解双十一天猫购买化妆品的人员中平均消费额度是多少(这可能有利于对商品价格区间的定位):或者不同年龄段的化妆品消费占比是多少(这可能有助于对商品备货量的预估). ...
- Docker - 解决同步容器与主机时间报错:Error response from daemon: Error processing tar file(exit status 1): invalid symlink "/usr/share/zoneinfo/UTC" -> "../usr/share/zoneinfo/Asia/Shanghai"
问题背景 这里讲解了如何同步容器和主机的时间:https://www.cnblogs.com/poloyy/p/13967532.html 其中使用方法二 docker cp /etc/localti ...
- martini-能量最小化参数(mdp文件)
1 ; 2 ; STANDARD MD INPUT OPTIONS FOR MARTINI 2.x 3 ; Updated 02 feb 2013 by DdJ 4 ; 5 ; for use wit ...