题目地址: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]特技飞行的更多相关文章

  1. luogu P5302 [GXOI/GZOI2019]特技飞行

    传送门 强行二合一可还行 首先\(c\)的贡献是不会变的,先考虑求出多少交点被矩形覆盖,交点的话可以按左端点纵坐标从下到上顺序枚举一条线段,然后维护右端点纵坐标的set,把之前处理过线段的右端点放进s ...

  2. 题解-GXOI/GZOI2019 特技飞行

    Problem loj3085 bzoj不放题面差评 题意概要:给出两条竖直直线,再给出 \(n\) 架飞机的初始航线:一条接通这两条直线的线段,保证航线交点不在两条直线上.现要求安排所有飞机在航线相 ...

  3. [GXOI/GZOI2019]特技飞行

    题目链接 [https://www.luogu.org/problem/P5302] 思路:这道题可以说是两道题的合并.注意到\(c\)的分数与 \(a\)和\(b\)的分数 无关,也就是说可以分成两 ...

  4. [GX/GZOI2019]特技飞行(扫描线+置换)

    感觉是6题中最难的一题,其实这题是一个二合一: 第一问:给定平面上若干点和k个关键点,关键点覆盖一个45°倾斜的正方形范围r,求有多少点被至少一个关键点覆盖.这个可以曼哈顿转切比雪夫距离,然后再扫描线 ...

  5. GXOI/GZOI2019题解

    GXOI/GZOI2019题解 P5300 [GXOI/GZOI2019]与或和 一眼题.. 显然枚举每个二进制位,答案就变成了全1子矩阵数量. 这个xjb推推,单调栈一下就行了. #include& ...

  6. Loj #3085. 「GXOI / GZOI2019」特技飞行

    Loj #3085. 「GXOI / GZOI2019」特技飞行 题目描述 公元 \(9012\) 年,Z 市的航空基地计划举行一场特技飞行表演.表演的场地可以看作一个二维平面直角坐标系,其中横坐标代 ...

  7. 【LOJ】#3085. 「GXOI / GZOI2019」特技飞行

    LOJ#3085. 「GXOI / GZOI2019」特技飞行 这显然是两道题,求\(C\)是一个曼哈顿转切比雪夫后的线段树扫描线 求\(AB\),对向交换最大化和擦身而过最大化一定分别为最大值和最小 ...

  8. 「GXOI / GZOI2019」简要题解

    「GXOI / GZOI2019」简要题解 LOJ#3083. 「GXOI / GZOI2019」与或和 https://loj.ac/problem/3083 题意:求一个矩阵的所有子矩阵的与和 和 ...

  9. BZOJ2697: 特技飞行

    2697: 特技飞行 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 607  Solved: 363[Submit][Status] Descript ...

随机推荐

  1. python3.6新特性

    print(f'{6:^30}') print('\n'.join([' '.join([f'{i}*{j}={i*j:2d}' for j in range(1,i+1)]) for i in ra ...

  2. Tutorial 03_分布式数据库HBASE

    (一)编程实现一下内容,并用Hadoop提供的Shell命令完成相同任务: 编程实现: (1)列出HBase所有表的相关信息,例如表名; package tutorial01; import java ...

  3. Excel提取字符串示例

    1.提取两个字符中间的字

  4. jquery ajax几种书写方式的总结

    Ajax在前端的应用极其广泛,因此,我们有必要对其进行总结,以方便后期的使用. AJAX优点: 可以异步请求服务器的数据,实现页面数据的实时动态加载, 在不重新加载整个页面的情况下,可以与服务器交换数 ...

  5. Jetson TX1 compile pytorch issues

    1. c++: internal compiler error: Killed (program cc1plus) reason: memory out, need swapfile 2. NCCL ...

  6. linux shell通配符及if语句判断

    $# 是传给脚本的参数个数 $0 是脚本本身的名字$1 是传递给该shell脚本的第一个参数$2 是传递给该shell脚本的第二个参数$@ 是传给脚本的所有参数的列表$* 是以一个单字符串显示所有向脚 ...

  7. zabbix SNMP OID列表

    系统参数(1.3.6.1.2.1.1) OID 描述 备注 请求方式 .1.3.6.1.2.1.1.1.0 获取系统基本信息 SysDesc GET .1.3.6.1.2.1.1.3.0 监控时间 s ...

  8. python@wraps实现原理

    @wraps作用 python中的装饰器装饰过的函数其实就不是函数本身了,我们可以看看下面的例子 import time def timmer(func): """tim ...

  9. MySQL数据库、表常用操作

    1.按条件查询表中数据: mysql> select user,host,password from user; 2.按组合条件查询表中数据: mysql> select id, pass ...

  10. Apache POI 示例

    Apache POI 3.17 Javadocs 用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office(Excel.WO ...