半平面求交 - 洛谷 - P3256 [JLOI2013] 赛车

news2024/11/27 20:39:54

欢迎关注更多精彩
关注我,学习常用算法与数据结构,一题多解,降维打击。

往期相关背景点击前往

题目大意

题目链接
https://www.luogu.com.cn/problem/P3194

有一场赛车比赛,每辆车有自己的起位置和速度,比赛时间无限长。

问题是求有哪些车辆跑在最前面。

解析

在这里插入图片描述
在直角坐标系中画出直线代表每辆车的状态。

每个时刻,处在最高处的车辆就是最前在的车辆。

所有时刻组成的图形是一个半平在交,所有半平面交的边就是领先过的车辆。

由于比赛时刻是从0开始,需要加一条负Y轴来限制。

注意:有些车辆的起位置和速度是相同的,需要去重。

代码


#include<stdio.h>
#include<cmath>
#include <algorithm>
#include <vector>
#include <list>
#include <cstring>
#include <set>
#include <map>


using namespace std;
const double EPS = 1e-6;
const double EPS2 = 0;

const int N = 1e6 + 10;
const int M = 1e6 + 10;

int cmp(double d) {
	if (abs(d) < EPS)return 0;
	if (d > 0)return 1;
	return -1;
}

class Point {
public:
	double x, y;
	int id;

	Point() {}
	Point(double a, double b) :x(a), y(b) {}
	Point(const Point& p) :x(p.x), y(p.y), id(p.id) {}

	void in() {
		scanf("%lf %lf", &x, &y);
	}
	void out() {
		printf("%f %f\n", x, y);
	}

	double dis() {
		return sqrt(x * x + y * y);
	}

	double dis2() {
		return x * x + y * y;
	}

	Point operator -() const {
		return Point(-x, -y);
	}

	Point operator -(const Point& p) const {
		return Point(x - p.x, y - p.y);
	}

	Point operator +(const Point& p) const {
		return Point(x + p.x, y + p.y);
	}
	Point operator *(double d)const {
		return Point(x * d, y * d);
	}

	Point operator /(double d)const {
		return Point(x / d, y / d);
	}


	void operator -=(Point& p) {
		x -= p.x;
		y -= p.y;
	}

	void operator +=(Point& p) {
		x += p.x;
		y += p.y;
	}
	void operator *=(double d) {
		x *= d;
		y *= d;
	}

	void operator /=(double d) {
		this ->operator*= (1 / d);
	}

	bool operator<(const Point& a) const {
		return x < a.x || (abs(x - a.x) < EPS && y < a.y);
	}

	bool operator==(const Point& a) const {
		return abs(x - a.x) < EPS && abs(y - a.y) < EPS;
	}
};

// 向量操作

double cross(const Point& a, const Point& b) {
	return a.x * b.y - a.y * b.x;
}

double dot(const Point& a, const Point& b) {
	return a.x * b.x + a.y * b.y;
}


class Line {
public:
	Point front, tail;
	int ind;
	Line() {}
	Line(const Point &a, const Point &b) :front(a), tail(b) {}
	Line(const Point &a, const Point &b, int i) :front(a), tail(b), ind(i) {}
};

int cmp(const Line& a, const Line& b) {
	//auto ta = atan2(a.front.y - a.tail.y, a.front.x - a.tail.x);
	//auto tb = atan2(b.front.y - b.tail.y, b.front.x - b.tail.x);

	// return cmp(ta - tb);

	return cmp(a.front.y - a.tail.y - (b.front.y - b.tail.y));
}


// 点在直线哪一边>0 左边,<0边
int SideJudge(const Line& a, const Point& b) {
	if (cross(a.front - a.tail, b - a.tail) < 0)return -1;
	return 1;
}


int LineSort(const Line& a, const Line& b) {
	int c = cmp(a, b);
	if (c)return c < 0;
	return a.tail.y > b.tail.y;
}

/*
点p 到 p+r 表示线段1
点q 到 q+s 表示线段2
线段1 上1点用 p' = p+t*r (0<=t<=1)
线段2 上1点用 q' = q+u*s (0<=u<=1)
让两式相等求交点 p+t*r = q+u*s
两边都叉乘s
(p+t*r)Xs = (q+u*s)Xs
pXs + t*rXs = qXs
t = (q-p)Xs/(rXs)
同理,
u = (p-q)Xr/(sXr) -> u = (q-p)Xr/(rXs)

以下分4种情况:
1. 共线,sXr==0 && (q-p)Xr==0, 计算 (q-p)在r上的投影在r长度上的占比t0,
计算(q+s-p)在r上的投影在r长度上的占比t1,查看[t0, t1]是否与范围[0,1]有交集。
如果t0>t1, 则比较[t1, t0]是否与范围[0,1]有交集。
t0 = (q-p)*r/(r*r)
t1 = (q+s-p)*r/(r*r) = t0 + s · r / (r · r)
2. 平行sXr==0 && (q-p)Xr!=0
3. 0<=u<=1 && 0<=t<=1 有交点
4. 其他u, t不在0到范围内,没有交点。
*/
pair<double, double> intersection(const Point& q, const Point& s, const Point& p, const Point& r) {
	// 计算 (q-p)Xr
	auto qpr = cross(q - p, r);
	auto qps = cross(q - p, s);

	auto rXs = cross(r, s);
	if (cmp(rXs) == 0)return { -1, -1 }; // 平行或共线
	// 求解t, u
	// t = (q-p)Xs/(rXs)
	auto t = qps / rXs;

	// u = (q-p)Xr/(rXs)
	auto u = qpr / rXs;

	return { u, t };
}

Point LineCross(const Line &a, const Line &b) {
	Point dira = a.front - a.tail;
	Point dirb = b.front - b.tail;

	auto p = intersection(a.tail, dira, b.tail, dirb);
	return a.tail + dira*p.first;
}

class HalfPlane {
public:
	vector<Line> lines;

	void addLine(const Line &a) {
		lines.push_back(a);
	}

	set<int> run() {
		sort(lines.begin(), lines.end(), LineSort);
		vector<int> q(lines.size()+10);
		vector<Point> t(lines.size()+10);

		int l = -1, r = 0;
		q[0] = 0;
		for (int i = 1; i < lines.size(); ++i) {
			if (cmp(lines[i], lines[i - 1]) == 0)continue;
			while (r - l > 1 && SideJudge(lines[i], t[r]) < 0)r--;
			while (r - l > 1 && SideJudge(lines[i], t[l+2]) < 0)l++;
			q[++r] = i;
			t[r] = LineCross(lines[q[r]], lines[q[r - 1]]);
		}
		/*while (r - l > 1 && SideJudge(lines[q[l + 1]], t[r]) < 0)r--;
		t[r+1] = LineCross(lines[q[l+1]], lines[q[r]]);
		r++;*/
		// 统计交点
		/*
		l++;
		vector<Point> ans(r-l);
		for (int i = 0; i < ans.size(); ++i) {
			ans[i] = t[i + l + 1];
		}*/

		set<int> ans;
		for (int i = l + 1; i <= r; ++i) ans.insert(lines[q[i]].ind);
		return ans;
	}
};

Point oiPs[N];
int position[N], volocity[N];
int carBelong[N];

void  solve() {
	int n;
	scanf("%d", &n);
	HalfPlane hp;
	
	for (int i = 0; i < n; ++i) scanf("%d", position+i);
	for (int i = 0; i < n; ++i) scanf("%d", volocity+i);
	hp.addLine({ Point(0, -1), Point(0, 0), 0});
	map<pair<int, int>, int> numInd;

	for (int i = 0; i < n; ++i) {
		pair<int, int> ele(position[i], volocity[i]);
		if (numInd.count(ele) > 0) {
			carBelong[i] = numInd[ele];
			continue;
		}

		carBelong[i] = numInd.size() + 1;
		numInd[ele] = numInd.size() + 1;

		Line l(Point( 1, position[i]+volocity[i]), Point(0, position[i]), carBelong[i]);
		hp.addLine(l);
	}

	auto seeLine = hp.run();
	vector<int> ans;
	for (int i = 0; i < n; ++i) {
		if (seeLine.count(carBelong[i]))ans.push_back(i + 1);
	}

	printf("%d\n", ans.size());
	for (int i = 0; i < ans.size(); ++i) {
		if (i)putchar(' ');
		printf("%d", ans[i]);
	}
	puts("");
}


int main() {
	solve();
	return 0;

}

/*

*/


本人码农,希望通过自己的分享,让大家更容易学懂计算机知识。创作不易,帮忙点击公众号的链接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1216449.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

目标检测一 SSD代码复现

SSD 背景 这是一种 single stage 的检测模型&#xff0c;相比于R-CNN系列模型上要简单许多。其精度可以与Faster R-CNN相匹敌&#xff0c;而速度达到了惊人的59FPS&#xff0c;速度上完爆 Fster R-CNN。 速度快的根本原因在于移除了 region proposals 步骤以及后续的像素采样或…

《持续交付:发布可靠软件的系统方法》- 读书笔记(十五)

持续交付&#xff1a;发布可靠软件的系统方法&#xff08;十五&#xff09; 第 15 章 持续交付管理15.1 引言15.2 配置与发布管理成熟度模型15.3 项目生命周期15.3.1 识别阶段15.3.2 启动阶段15.3.3 初始阶段15.3.4 开发与发布15.3.5 运营阶段 15.4 风险管理流程15.4.1 风险管理…

微星迫击炮b660m使用intel arc a750/770显卡功耗优化方法

bios 优化: 1,开机后持续点击“delete”键直到进入微星bios。 2,点击右上角选择我们熟悉的中文。 3,点击Settings--->高级---> pcie/Pci子系统设置 4,Native PCIE Enable : Enabled Native Aspm:允许

从零开始 通义千问大模型本地化到阿里云通义千问API调用

从零开始 通义千问大模型本地化到阿里云通义千问API调用 一、通义千问大模型介绍 何为“通义千问”&#xff1f; “通义千问大模型”是阿里云推出的一个超大规模的语言模型&#xff0c;具有强大的归纳和理解能力&#xff0c;可以处理各种自然语言处理任务&#xff0c;包括但…

Xrdp+Cpolar实现远程访问Linux Kali桌面

XrdpCpolar实现远程访问Linux Kali桌面 文章目录 XrdpCpolar实现远程访问Linux Kali桌面前言1. Kali 安装Xrdp2. 本地远程Kali桌面3. Kali 安装Cpolar 内网穿透4. 配置公网远程地址5. 公网远程Kali桌面连接6. 固定连接公网地址7. 固定地址连接测试 前言 Kali远程桌面的好处在于…

ZYNQ_project:test_fifo_255X8

首先&#xff0c;这个vivado的fifo和quartus有很大不同。 用BRAM来实现异步fifo。 vivado的fifo有复位&#xff0c;在时钟信号稳定后&#xff0c;复位至少三个时钟周期&#xff08;读写端口的慢时钟&#xff09;&#xff0c;复位完成后30个时钟周期后再进行写操作&#xff08…

【UE5】物体沿样条线移动

目录 效果 步骤 一、使用样条线创建路径 二、创建沿样条线路径移动的物体 三、定义可移动物体的生成器 效果 步骤 一、使用样条线创建路径 先创建一个Actor蓝图&#xff0c;这里命名为“BP_Line” 该蓝图中只需添加一个样条组件 将“BP_Line”拖入场景中 按住Alt鼠标左键…

如何制定LinkedIn商进行品牌推广?

在网络上脱颖而出不是一件简单的事。不仅有比以往更多的平台、算法和内容类型&#xff0c;而且还有更多的企业在争夺注意力。据统计&#xff0c;每天有超过 270 万家公司在 LinkedIn 上发布信息。 策略很重要&#xff0c;尤其是在 LinkedIn 营销领域。下面将为你总结LinkedIn 营…

Spring Cloud与Spring Cloud Alibaba怎么正确引入依赖版本

一.Spring Cloud与Spring Cloud Alibaba与Springboot各版本的依赖关系 我们可以去springcloud alibaba的github仓库中的说明中查找到三个依赖版本的对应关系&#xff1a; 版本说明 alibaba/spring-cloud-alibaba Wiki GitHub 二.通过BOM对Spring Cloud与Spring Cloud Alib…

三江城115m²3室2厅2卫,现代简约不单是居所更是对生活的向往。福州中宅装饰,福州装修

【前言】 简洁有力&#xff0c;静默无声。 以简约精致的方式&#xff0c;展现现代都市生活&#xff1b; 经典不因潮流褪色&#xff0c;不为悦人只为悦己。 项目信息 项目名称 | 三江城 设计地址 | 福建福州 项目面积 | 115㎡ 项目户型 | 3室2厅 设计风格 | 现代简约 全…

BananaPi BPI-M6(Raspberry Pi 5) Android 平板电脑镜像测试温度

我已经在本文中介绍了 全新的Banana Pi BPI-M6&#xff0c;并讨论了其与Raspberry Pi 5的硬件特性比较。 然后我将 Android 平板电脑固件上传到 eMMC&#xff0c;从而使 Banana Pi 实际可用。一开始有点坎坷&#xff0c;但文章中有更多内容。 在另一台电脑上&#xff0c;一切都…

ubuntu 20.04安装 Anaconda教程

在安装Anaconda之前需要先安装ros(防止跟conda冲突&#xff0c;先装ros)。提前安装好cuda 和cudnn。 本博客参考&#xff1a;ubuntu20.04配置ros noetic和cuda&#xff0c;cudnn&#xff0c;anaconda&#xff0c;pytorch深度学习的环境 安装完conda后&#xff0c;输入: pyth…

在 HarmonyOS 上使用 ArkUI 实现计步器应用

介绍 本篇 Codelab 使用 ArkTS 语言实现计步器应用&#xff0c;应用主要包括计步传感器、定位服务和后台任务功能&#xff1a; 1. 通过订阅计步器传感器获取计步器数据&#xff0c;处理后显示。 2. 通过订阅位置服务获取位置数据&#xff0c;处理后显示。 3. 通过服务开…

vue2 mixin的方式 大屏适配(缩放居中的方式)

使用要求&#xff1a;指定容器的 id 为 bigScreenContainer 一、效果图 不管你的屏幕多大都会根据设计稿 1920*1080 进行缩放 图一&#xff1a;缩小的效果 图二&#xff1a;放大的效果 二、使用方式 <template><div id"bigScreenContainer" ref"big…

又在为年会头疼了?看易知微教你用数据可视化搭建工具制作年会抽奖大屏!

距离过年还有2个多月&#xff0c;但是各个公司的行政、组织部门已经接到了年会策划的通知&#xff0c;年会是公司内部重要的社交盛事之一&#xff0c;不仅可以展示公司的实力和成绩&#xff0c;还可以加强员工之间的沟通和团队合作意识。好的年会策划不仅要注重细节&#xff0c…

欧盟铅镉RSL邻苯项目化学物质检测报告办理(RSL Report 资质)REACH 认证

如果您在亚马逊上销售商品&#xff0c;则必须遵守所有适用的欧盟和地方法律法规&#xff0c;以及适用于这些商品和商品信息的亚马逊政策。要在亚马逊上销售某些商品&#xff0c;)您需要向我们提供 REACH 符合性声明或检测报告。 RSL-Phthalate资质 欧盟RSL邻苯项目检测报告 Ph…

一张图系列 - “position_embedding”

关于位置编码&#xff0c;我感觉应该我需要知道点啥&#xff1f; 0、需要知道什么知识&#xff1f; multi head atten 计算 复数的常识 1、embedding 是什么&#xff1f; position embedding常识、概念&#xff0c;没有会怎样&#xff1f; 交换token位置&#xff0c;没有P…

keil程序载入硬件成功,但未按代码执行

可能是因为keil版本的问题 1.在个人电脑上测试&#xff0c;安装keil软件如下。 2.测试stlinkv2仿真器&#xff0c;A202208\A202303\A202210,对1号和2号M3核心板验证。皆下载成功并执行程序。 程序如下: #include "stm32f10x.h" void delay_nms(u16 time); int ma…