题解-GXOI/GZOI2019 特技飞行

Problem

loj3085 bzoj不放题面差评

题意概要:给出两条竖直直线,再给出 \(n\) 架飞机的初始航线:一条接通这两条直线的线段,保证航线交点不在两条直线上。现要求安排所有飞机在航线相交处做特技:

  • 擦身而过:两架飞机按原方向线路继续前进,一次得分 \(b\)
  • 对向交换:两架飞机交换线路继续前进,一次得分 \(a\)

另外,给定 \(k\) 个边界与坐标轴成 \(45°\)角 的正方形,若一次特技被至少一个正方形囊括,则总得分加 \(c\)

现要求决策每次相遇做的特技,求最大/最小收益

同时要求决策方案中所有飞机 在两条竖直直线处 按纵坐标的排序 相同

\(n, Q\leq 10^5\)

交点个数 \(\leq 5\times 10^5\)

这题意概要好像和原题面差不多了qwq

Solution

\(\mathrm{GXOI/GZOI2019}\) 的题好毒瘤啊,两道联赛、两道原题、一道麻将题……完全不想打,就这题还有点意思……还偏偏要整个二合一……

交点个数 \(\leq 5\times 10^5\),应该是暗示要暴力求出来:交点一定是右部直线排序的逆序对(左部已经有序),用个 \(set\) 暴力扫就是 \(O(n\log n)\)。就得到了所有交点

\(c\) 的贡献很明显是单独求的,将坐标系旋转 \(45°\) 后就可以扫描线了。所以其实难度在于如何求 \(a,b\) 的贡献

设交点总数为 \(t\),其中有 \(x\) 个点交换航线,\(t-x\) 个点不交换。这部分贡献是 \(ax+b(t-x)=(a-b)x+bt\),所以总得分的最大最小值一定是 \(x\) 取最值时取得,即只需要求最少/多有多少个点交换航线

首先因为要求飞机在起终点的顺序不变,而交换航线不会改变顺序,所有点都交换航线肯定是可行的,即 \(x_{\max}=t\)

再考虑最小值。假如所有点都不换航线(\(x = 0\)),在大部分情况下都不合法,考虑使用最少的交换航线使得最终状态与初始状态一致:可以发现,若按照原航线行进时,飞机状态的变化产生了 \(s_1\rightarrow s_2\rightarrow ...\rightarrow s_m\rightarrow s_1\) 的循环,则可以使用 \(m-1\) 次交换使得方案合法(一次交换可以使得一架且最多一架飞机到达指定位置,使 \(m-1\) 架飞机合法后剩下的那一架飞机也即合法)

那么需要交换的次数为 "\(n-\)循环的个数"

复杂度为 \(O(n\log n+k\log k)\),瓶颈在暴力找交点和扫描线

Code

代码中 get_cross 为暴力找交点,Circle 为找循环,Extra 为扫描线

#include <bits/stdc++.h>
using namespace std;

inline void read(int&x){
    char c11=getchar();x=0;while(!isdigit(c11))c11=getchar();
    while(isdigit(c11))x=x*10+c11-'0',c11=getchar();
}

const double eps = 1e-6;
const int N = 101000, M = 501000;

int l0[N], r0[N];
int n,L,R;

struct pnt {
    double x, y;
    friend inline bool operator < (const pnt&A,const pnt&B) {return A.x < B.x;}
}p[M];

int p0;

pnt crs(int i,int j) {
    double th = (double)abs(l0[i] - l0[j]) / (abs(l0[i] - l0[j]) + abs(r0[i] - r0[j]));
    return (pnt) {L + (R-L) * th, l0[i] + (r0[i] - l0[i]) * th};
}

set <int> c;
set <int> :: iterator itr;
map <int,int> mp;

int get_cross() {
    for(int i=1;i<=n;++i) {
        c.insert(r0[i]);
        mp[r0[i]] = i;
        itr = c.find(r0[i]);
        for(++itr; itr != c.end(); ++itr) {
            int j = mp[*itr];
            p[++p0] = crs(i, j);
        }
    }
    return p0;
}

namespace Circle {
    int b[N], dad[N];
    int find(int x) {return dad[x] ? dad[x] = find(dad[x]) : x;}
    int main() {
        for(int i=1;i<=n;++i) b[i] = r0[i];
        sort(b+1,b+n+1);
        int res = 0;
        for(int i=1,j,p1,p2;i<=n;++i) {
            j = lower_bound(b+1,b+n+1,r0[i])-b;
            if((p1 = find(i)) == (p2 = find(j))) ++res;
            else dad[p1] = p2;
        }
        return p0 - (n - res);
    }
}

namespace Extra {
    double b[M+N+N];
    int Q, tot;

    struct LNE {
        double x, y1, y2; int w;
        friend inline bool operator < (const LNE&A,const LNE&B) {return A.x < B.x;}
    }l[N+N];

    namespace BIT {
        #define lb(x) (x&(-x))
        int d[M+N+N];
        inline int qry(int x) {
            int res = 0;
            for(int i=x;i;i-=lb(i)) res += d[i];
            return res;
        }
        inline void upd(int l, int r, int w) {
            for(;l<=tot;l+=lb(l)) d[l] += w;
            for(++r;r<=tot;r+=lb(r)) d[r] -= w;
        }
        #undef lb
    }

    void input() {
        double x, y;
        for(int i=1;i<=p0;++i) {
            x = p[i].x, y = p[i].y;
            p[i].x = x + y, p[i].y = x - y;
            b[++tot] = p[i].y;
        }
        sort(p+1,p+p0+1);
        int r; read(Q);
        for(int i=1;i<=Q;++i) {
            scanf("%lf%lf",&x,&y), read(r);
            l[i+i-1].x = x + y - r - eps;
            l[i+i-1].y1 = x - r - y - eps;
            l[i+i-1].y2 = x - y + r + eps;
            l[i+i-1].w = 1;
            l[i+i].x = x + y + r + eps;
            l[i+i].y1 = x - y - r - eps;
            l[i+i].y2 = x + r - y + eps;
            l[i+i].w = -1;

            b[++tot] = x - y + r + eps;
            b[++tot] = x - y - r - eps;
        }
        Q <<= 1;
        sort(l+1,l+Q+1);

        sort(b+1,b+tot+1);
        int tt0 = 0; b[0] = -1e10;
        for(int i=1;i<=tot;++i)
            if(fabs(b[i] - b[i-1]) > eps)
                b[++tt0] = b[i];
        tot = tt0;

        for(int i=1;i<=p0;++i) p[i].y = lower_bound(b+1,b+tot+1,p[i].y) - b;
        for(int i=1;i<=Q;++i) {
            l[i].y1 = lower_bound(b+1,b+tot+1,l[i].y1) - b;
            l[i].y2 = lower_bound(b+1,b+tot+1,l[i].y2) - b;
        }
    }

    int main() {
        input();

        int res = 0;
        for(int i=1,j=1;i<=p0;++i) {
            while(j <= Q and l[j].x <= p[i].x)
                BIT::upd(l[j].y1, l[j].y2, l[j].w), ++j;
            if(BIT::qry(p[i].y)) ++res;
        }
        return res;
    }
}

int main() {
    int A, B, C;
    read(n), read(A), read(B), read(C);
    read(L), read(R);
    for(int i=1;i<=n;++i) read(l0[i]);
    for(int i=1;i<=n;++i) read(r0[i]);

    int ans1 = A * get_cross(), ans2 = ans1, exa;
    ans2 += (B - A) * Circle::main();
    exa = C * Extra::main();
    if(ans1 > ans2) swap(ans1, ans2);
    printf("%d %d\n",ans1 + exa, ans2 + exa);
    return 0;
}

原文地址:https://www.cnblogs.com/penth/p/10777150.html

时间: 2024-11-07 08:31:02

题解-GXOI/GZOI2019 特技飞行的相关文章

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

感觉是6题中最难的一题,其实这题是一个二合一: 第一问:给定平面上若干点和k个关键点,关键点覆盖一个45°倾斜的正方形范围r,求有多少点被至少一个关键点覆盖.这个可以曼哈顿转切比雪夫距离,然后再扫描线求解,复杂度O(nlogn) 第二问:求最少和最多有多少次擦肩而过.显然每个交点都可以做对向交换,这是最少擦肩而过的次数.最多的次数,假设全部擦肩而过得到排列p,对向交换实际上是交换两元素位置,用最小交换次数还原排列即可. #include<bits/stdc++.h> using namespa

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

Loj #3085. 「GXOI / GZOI2019」特技飞行 题目描述 公元 \(9012\) 年,Z 市的航空基地计划举行一场特技飞行表演.表演的场地可以看作一个二维平面直角坐标系,其中横坐标代表着水平位置,纵坐标代表着飞行高度. 在最初的计划中,这 \(n\) 架飞机首先会飞行到起点 \(x = x_{st}\) 处,其中第 \(i\) 架飞机在起点处的高度为 \(y_{i,0}\).它们的目标是终点 \(x = x_{ed}\) 处,其中第 \(i\) 架飞机在终点处的高度应为 \(y

2697: 特技飞行

2697: 特技飞行 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 646  Solved: 393[Submit][Status] Description 神犇航空开展了一项载客特技飞行业务.每次飞行长N个单位时间,每个单位时间可以进行一项特技动作,可选的动作有K种,每种动作有一个刺激程度Ci.如果连续进行相同的动作,乘客会感到厌倦,所以定义某次动作的价值为(距上次该动作的时间)*Ci,若为第一次进行该动作,价值为0.安排一种方案,使得总价值最

bzoj2697特技飞行*

bzoj2697特技飞行 题意: N个单位时间,每个单位时间可以进行一项特技动作,可选的动作有K种,每种动作有一个刺激程度Ci.每次动作的价值为(距上次该动作的时间)*Ci,若为第一次进行该动作,价值为0.求最大总价值.N≤1000,K≤300. 题解: 因为如果同个动作做3次,不如只做头尾两次更好.所以把动作按Ci降序排序,把Ci大的尽量放在两端. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algori

BZOJ 2697 特技飞行(贪心)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2697 [题目大意] 神犇航空开展了一项载客特技飞行业务. 每次飞行长N个单位时间,每个单位时间可以进行一项特技动作, 可选的动作有K种,每种动作有一个刺激程度Ci. 如果连续进行相同的动作,乘客会感到厌倦, 所以定义某次动作的价值为(距上次该动作的时间)*Ci,若为第一次进行该动作,价值为0. 安排一种方案,使得总价值最大. [题解] 我们发现一个动作进行两遍收益才是最大的,进行第三

BZOJ2697: 特技飞行

2697: 特技飞行 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 607  Solved: 363[Submit][Status] Description 神 犇航空开展了一项载客特技飞行业务.每次飞行长N个单位时间,每个单位时间可以进行一项特技动作,可选的动作有K种,每种动作有一个刺激程度Ci.如果连 续进行相同的动作,乘客会感到厌倦,所以定义某次动作的价值为(距上次该动作的时间)*Ci,若为第一次进行该动作,价值为0.安排一种方案,使得总价

[LuoguP5305][GXOI/GZOI2019]旧词 (树链剖分)

[GXOI/GZOI2019]旧词 (树链剖分) 题面 给定一棵 \(n\)个点的有根树,节点标号 \([1,n]\),1号节点为根. 给定常数\(k\) 给定\(Q\)个询问,每次询问给定\(x,y\),求:\(\sum_{i=1}^x \mathrm{deep}(\mathrm{lca}(i,y)) \mod 998244353\) 分析 此题为[BZOJ3626] [LNOI2014]LCA(树链剖分)的加强版. 考虑原来的做法(k=1):我们把i到根的路径上所有点+1,y到根路径上的权值

题解 P5301 【[GXOI/GZOI2019]宝牌一大堆】

这道题除了非常恶心以外也没有什么非常让人恶心的地方 当然一定要说有的话还是有的,就是这题和咱 ZJOI 的 mahjong 真的是好像的说~ 于是就想说这道题出题人应该被 锕 掉 noteskey 整体的思路就是特判国士无双和七对子,然后 dp 搞普通的胡牌 dp 状态设计和楼上大佬说的一样,就是用一个五维的 \(f[i][j][k][l][p]\) 表示当前处理了前 i 种类型的牌,存在 j 个 面子/杠子 ,以 i-1 开头的顺子要选 k 个,以 i 开头的面子要选 l 个,以及当前是否有

题解:[GXOI/GZOI2019]旅行者

调这个题调了两个月,被自己蠢哭 题意: 给一个有向图,一组关键点,求关键点之间的最短的距离 Solution: 这个题目有两种做法,分别是 $nlogn$ 和 $nlog^2n$ 的 首先说 $nlogn$ 的官方做法,我们考虑多源迪杰斯特拉 正图上从 k 个关键点出发跑 $dijkstra$ ,记某个点离最近的关键点距离为 $dis[0][i]$ 反图上也从 k 个关键点出发跑 $dijkstra$ ,距离记为 $dis[1][i]$ 枚举正图中的边 $u->v: w$, 用 $dis[0][