P5302 [GXOI/GZOI2019]特技飞行
题目地址:P5302 [GXOI/GZOI2019]特技飞行
这里是官方题解(by lydrainbowcat)
题意
给 \(10^5\) 条直线,给 \(x = st\) 和 \(x = ed\) 两个位置
在两条直线 \(l1,l2\) 交点,可以交换 \(l1,l2\) 接下来的部分(变成两条折线)
交换或不交换分别可以获得固定的分数 \(a\) 和 \(b\)
另外有 \(10^5\) 个观测点可以观测到一定范围内情况(曼哈顿距离),在观测范围内的点额外计分 \(c\)
要求最后在 \(x = st\) 处和 \(x = ed\) 处,直线保持相同的顺序
问如何交换可以获得最高的得分。保证交点小于等于 \(5*10^5\) 个
解法
这其实是两个题的拼接
首先,若 \(a>b\) ,说明交换越多越好。实际上所有交点都可以交换,因为交点个数恰好是逆序对数,所有逆序对都交换一下最后正好变成正序
若 \(a<b\) ,交换次数为 $n - $ 置换数,因为每个置换之间的互相独立的,可以不参与交换。每个置换内部其实都等价于一个环(5-1-2-3-4这样的),交换次数为 \(len-1\) ,故总次数为 $\sum (len - 1) = n - $ 置换数。
所有交点可以用类似于排序的方法 \(O(n)\) 预处理,坐标转 \(45\) 度
接下来就是若干个点(事件),还有若干个正方形(拆成两个事件)的扫描线问题
扫描线 + 树状数组即可
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#define MAX_NR 100010
const long double eps = 1e-9;
int N, A, B, C, ST_X, ED_X, M;
struct Point {
long double x, y;
Point() = default;
Point(int x_, int y_) :
x(x_), y(y_) {}
Point(long double x_, long double y_) :
x(x_), y(y_) {}
} point[MAX_NR * 2];
struct Event {
long double x;
int y0, y1, op;
Event() = default;
Event(int x_, int y0_, int y1_, int op_) :
x(x_), y0(y0_), y1(y1_), op(op_) {}
Event(long double x_, int y_) :
x(x_), y0(y_), y1(y_), op(0) {}
inline bool operator < (const Event &a) const {
if (fabs(x - a.x) > eps) {
return x < a.x;
} else if (op != a.op) {
return op > a.op;
} else {
return false;
}
}
};
std::vector<Point> inter;
inline Point get_intersection(Point a, Point b, Point c, Point d) {
long double a1 = b.y - a.y;
long double b1 = a.x - b.x;
long double c1 = a1 * a.x + b1 * a.y;
long double a2 = d.y - c.y;
long double b2 = c.x - d.x;
long double c2 = a2 * c.x + b2 * c.y;
long double determinant = a1 * b2 - a2 * b1;
if (determinant == 0) {
return { -1, -1 };
} else {
long double x = (b2*c1 - b1 * c2) / determinant;
long double y = (a1*c2 - a2 * c1) / determinant;
return { x, y };
}
}
namespace BIT {
int N;
int b[MAX_NR * 20];
void init(int n) {
N = n;
memset(b, 0, sizeof(b));
}
int query(int x) {
int res = 0;
for (int i = x; i > 0; i -= i & (-i)) {
res += b[i];
}
return res;
}
void update(int x, int v) {
for (int i = x; i <= N; i += i & (-i)) {
b[i] += v;
}
}
}
bool cmp(int i,int j) {
return point[N + i].y < point[N + j].y;
}
int main() {
scanf("%d%d%d%d%d%d", &N, &A, &B, &C, &ST_X, &ED_X);
for (int i = 0, x, y; i < N * 2; ++i) {
scanf("%d", &y);
x = (i < N ? ST_X : ED_X);
point[i] = { x, y };
}
std::vector<int> p(N), rank(N), a(N), v(N);
for (int i = 0; i < N; ++i) {
a[i] = rank[i] = i;
v[i] = 0;
}
std::sort(rank.begin(), rank.end(), cmp);
for (int i = 0; i < N; ++i) {
p[rank[i]] = i;
}
int nr_cross = N;
for (int i = 0; i < N; ++i) {
if (v[i]) continue;
nr_cross--;
int x = p[i];
while (x != i) {
v[x] = 1;
x = p[x];
}
}
for (int i = 0; i < N; ++i) {
for (int j = i; ; ++j) {
if (i == p[j]) {
int aj = a[j];
for (int k = j - 1; k >= i; --k) {
Point cur = get_intersection(
point[a[k]], point[a[k] + N],
point[aj], point[aj + N]);
inter.push_back(Point(cur.x + cur.y, cur.x - cur.y));
std::swap(p[k], p[k + 1]);
a[k + 1] = a[k];
}
break;
}
}
}
scanf("%d", &M);
std::vector<long double> Y(M * 2 + inter.size());
std::vector<Event> events(M * 2 + inter.size());
for (int i = 0, x, y, r; i < M; ++i) {
scanf("%d%d%d", &x, &y, &r);
int x_ = x, y_ = y;
x = x + y, y = x_ - y_;
events[i] = { x - r, y - r, y + r, 1 };
events[i + M] = { x + r, y - r, y + r, -1 };
Y[i] = y - r;
Y[i + M] = y + r;
}
for (int i = 0; i < inter.size(); ++i) {
Y[2 * M + i] = inter[i].y;
}
std::sort(Y.begin(), Y.end());
// Y.resize(std::unique(Y.begin(), Y.end()) - Y.begin());
int pos = 0;
for (int i = 0; i < Y.size(); i++)
if (i == 0 || fabs(Y[i] - Y[i - 1]) > eps) Y[pos++] = Y[i];
Y.resize(pos);
for (int i = 0; i < 2 * M; ++i) {
events[i].y0 = std::lower_bound(Y.begin(), Y.end(), events[i].y0) - Y.begin() + 1;
events[i].y1 = std::lower_bound(Y.begin(), Y.end(), events[i].y1) - Y.begin() + 1;
}
for (int i = 0; i < inter.size(); ++i) {
int y = std::lower_bound(Y.begin(), Y.end(), inter[i].y) - Y.begin() + 1;
events[2 * M + i] = { inter[i].x, y };
}
std::sort(events.begin(), events.end());
int nr_observed = 0;
BIT::init(2 * Y.size());
for (int i = 0; i < events.size(); i++) {
Event e = events[i];
if (e.op) {
BIT::update(e.y0, e.op);
BIT::update(e.y1 + 1, -e.op);
} else {
nr_observed += BIT::query(e.y0) > 0;
}
}
int nr_inv = inter.size();
int score_observed = nr_observed * C;
int max_score = A * nr_inv;
int min_score = A * nr_cross + B * (nr_inv - nr_cross);
if (A < B) {
std::swap(min_score, max_score);
}
std::cout << min_score + score_observed << ' ' << max_score + score_observed << std::endl;
return 0;
}
P5302 [GXOI/GZOI2019]特技飞行的更多相关文章
- luogu P5302 [GXOI/GZOI2019]特技飞行
传送门 强行二合一可还行 首先\(c\)的贡献是不会变的,先考虑求出多少交点被矩形覆盖,交点的话可以按左端点纵坐标从下到上顺序枚举一条线段,然后维护右端点纵坐标的set,把之前处理过线段的右端点放进s ...
- 题解-GXOI/GZOI2019 特技飞行
Problem loj3085 bzoj不放题面差评 题意概要:给出两条竖直直线,再给出 \(n\) 架飞机的初始航线:一条接通这两条直线的线段,保证航线交点不在两条直线上.现要求安排所有飞机在航线相 ...
- [GXOI/GZOI2019]特技飞行
题目链接 [https://www.luogu.org/problem/P5302] 思路:这道题可以说是两道题的合并.注意到\(c\)的分数与 \(a\)和\(b\)的分数 无关,也就是说可以分成两 ...
- [GX/GZOI2019]特技飞行(扫描线+置换)
感觉是6题中最难的一题,其实这题是一个二合一: 第一问:给定平面上若干点和k个关键点,关键点覆盖一个45°倾斜的正方形范围r,求有多少点被至少一个关键点覆盖.这个可以曼哈顿转切比雪夫距离,然后再扫描线 ...
- GXOI/GZOI2019题解
GXOI/GZOI2019题解 P5300 [GXOI/GZOI2019]与或和 一眼题.. 显然枚举每个二进制位,答案就变成了全1子矩阵数量. 这个xjb推推,单调栈一下就行了. #include& ...
- Loj #3085. 「GXOI / GZOI2019」特技飞行
Loj #3085. 「GXOI / GZOI2019」特技飞行 题目描述 公元 \(9012\) 年,Z 市的航空基地计划举行一场特技飞行表演.表演的场地可以看作一个二维平面直角坐标系,其中横坐标代 ...
- 【LOJ】#3085. 「GXOI / GZOI2019」特技飞行
LOJ#3085. 「GXOI / GZOI2019」特技飞行 这显然是两道题,求\(C\)是一个曼哈顿转切比雪夫后的线段树扫描线 求\(AB\),对向交换最大化和擦身而过最大化一定分别为最大值和最小 ...
- 「GXOI / GZOI2019」简要题解
「GXOI / GZOI2019」简要题解 LOJ#3083. 「GXOI / GZOI2019」与或和 https://loj.ac/problem/3083 题意:求一个矩阵的所有子矩阵的与和 和 ...
- BZOJ2697: 特技飞行
2697: 特技飞行 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 607 Solved: 363[Submit][Status] Descript ...
随机推荐
- 随心测试_软测基础_008<测试对象整体认识>
关于:软件测试的整体认识,首先:认识:测试 对象 与 测试主体(人) 之间的关系 核心理解如下: 不同的测试对象,选取 不同的测试方法 软件项目的周期中:提出 需求 ——>软件实现—— ...
- Git-删除文件后找回-比较文件差异
#前提:删除前,文件存在是的状态提交到了本地库#操作: git reset --hard 指针位置 删除操作已近提交到本地库:指针指向历史记录 linxianli@VM-QS- MINGW64 /c/ ...
- 不能完整读取txt文件问题
txt文件内容 5 1.3 0.4 3.4 -1.7 16.7 0.89 14.17 4.8 1.34 0.42 3.36 -2 16.2 0.9 14.8 4.9 1.30 0.37 3.51 -1 ...
- c#使用资源文件完成国际化
路径结构如下 namespace UnitTestProject1 { [TestClass] public class UnitTest1 { [TestMethod] public void Te ...
- WMI测试器
WMI是... 来自百度百科:WMI(Windows Management Instrumentation,Windows 管理规范)是一项核心的 Windows 管理技术:用户可以使用 WMI 管理 ...
- Java中的Null是什么?
对于Java程序员来说,null是令人头痛的东西.时常会受到空指针异常(NPE)的骚扰.连Java的发明者都承认这是他的一项巨大失误.Java为什么要保留null呢?null出现有一段时间了,并且我认 ...
- tensorflow-TensorBoard
Tensorborad--> 是Tensorflow的可视化工具,它可以通过Tensorflow程序运行过程中输出的日志文件可视化Tensorflow程序的运行状态.Tensorflow和Ten ...
- nodejs 搭建本地静态服务器
1. http-server 参看 https://www.npmjs.com/package/http-server 使用http-server搭建本地静态服务器 全局安装http-server n ...
- 差分约束 HDU - 1384 HDU - 3592 HDU - 1531 HDU - 3666
Intervals Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- python并发编程之多进程基础知识点
1.操作系统 位于硬件与应用软件之间,本质也是一种软件,由系统内核和系统接口组成 和进程之间的关系是: 进程只能由操作系统创建 和普通软件区别: 操作系统是真正的控制硬件 应用程序实际在调用操作系统提 ...