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

2023-11-23 14:11

本文主要是介绍Loj #3085. 「GXOI / GZOI2019」特技飞行,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

题目描述

公元 \(9012\) 年,Z 市的航空基地计划举行一场特技飞行表演。表演的场地可以看作一个二维平面直角坐标系,其中横坐标代表着水平位置,纵坐标代表着飞行高度。

在最初的计划中,这 \(n\) 架飞机首先会飞行到起点 \(x = x_{st}\) 处,其中第 \(i\) 架飞机在起点处的高度为 \(y_{i,0}\)。它们的目标是终点 \(x = x_{ed}\) 处,其中第 \(i\) 架飞机在终点处的高度应为 \(y_{i,1}\)。因此,每架飞机可以看作坐标系中的一个点,它的航线是从 \((x_{st},y_{i,0})\) 出发、到 \((x_{ed},y_{i,1})\) 结束的一条线段,如下图所示。

5cb2a2d6a8dc9.png

\(n\) 架飞机同时出发且始终保持一定的对地速度。因此,对于任意两条交叉的航线(线段),对应的两架飞机必然会同时到达交点处——这就是它们进行特技表演的时刻。它们将会偏转机翼,展现以极近的距离「擦身而过」特技,然后继续保持各自的航线

航空基地最近还研究了一种新的特技「对向交换」。当两架飞机到达交点处时,之前正在下降的那架立即转为执行抬升动作,之前正在上升的那架则执行一次空翻,两架飞机一上一下、机腹对机腹,同样以极近的距离经过交点,然后互相交换接下来的航线

我们不必关心特技动作在物理上究竟是如何实现的,飞机仍然看作一个点,在两种特技动作下,航线的变化如下图所示(\(y_{i,1}'\) 表示交换航线后第 \(i\) 架飞机在终点的新高度)。容易发现,「对向交换」会使它们的航线变为折线,并保持它们在纵坐标上的相对顺序;而「擦身而过」会改变它们在纵坐标上的相对顺序

5cb2a389b6bb8.png

现在,观看表演的嘉宾团提出了一个苛刻的要求——在终点 \(x = x_{ed}\) 处,按照高度排序,\(n\) 架飞机的相对顺序必须与 \(x = x_{st}\) 处的相对顺序一致。嘉宾团还给「对向交换」特技和「擦身而过」特技分别评定了难度系数 \(a\)\(b\),每次「对向交换」特技可以获得 \(a\) 的分数,每次「擦身而过」特技可以获得 \(b\) 的分数。

除此以外,嘉宾团共有 \(k\) 名成员,第 \(i\) 名成员会乘热气球停留在位置 \((p_i,q_i)\) 处,具有 \(r_i\) 的观测距离,可以观测到区域 \(|x - p_i| + |y - q_i| \le r_i\) 里的所有特技。

若某个交点处的特技被一名或多名嘉宾观测到,则可以获得 \(c\) 的额外加分。

注意:特技无论是否被观测到,均可以获得 \(a\) 或者 \(b\) 的得分

下图是对本题第一幅图 \(4\) 条航线 \(4\) 个交点的一种满足要求的安排,包括 \(2\) 次「对向交换」、\(2\) 次「擦身而过」,\(3\) 项特技被观测到,得分 \(2a + 2b + 3c\)。为了方便观察,图中展现「对向交换」特技的交点稍稍有些分离。

5cb2a5b2c7b4c.png

在这次的剧情里,你成为了 Z 市航空基地的规划员,你可以决定在每个交点处是执行「对向交换」还是「擦身而过」。你被要求在保证嘉宾团要求的前提下,计算整个特技表演的可能得到的最低和最高分数。

输入格式

第一行包含六个非负整数 \(n,a,b,c,x_{st},x_{ed}\),分别表示航线(线段)总数、「对向交换」特技的得分、「擦身而过」特技的得分、观测对表演的额外分、飞行起点的横坐标、飞行终点的横坐标。

第二行包含 \(n\) 个非负整数 \(y_{i,0}\),其中第 \(i\) 个数表示第 \(i\) 条航线起点的纵坐标,保证按照从低到高的顺序给出,即 \(y_{i,0} < y_{i + 1,0}\)

第三行包含 \(n\) 个非负整数 \(y_{i,1}\),其中第 \(i\) 个数表示第 \(i\) 条航线终点的纵坐标。

第四行包含一个非负整数 \(k\),表示嘉宾的数量。

接下来 \(k\) 行每行三个非负整数 \(p_i,q_i,r_i\),分别表示第 \(i\) 名嘉宾所在位置的横、纵坐标与观测距离。

输入数据对于所有航线(线段)在直线 \(x = x_{st}\)\(x = x_{ed}\) 之间的交点总数也有一些限制,详见「数据范围与提示」。

输出格式

输出只有一行,包含两个整数,表示整个特技飞行表演的可能得到的最低和最高分数,中间用一个空格隔开。

数据范围与提示

不存在三条或三条以上的线段交于同一点。

所有坐标和 \(r_i\) 均为 \(5 \times 10^7\) 以内的非负整数。

\(y_{i,0} < y_{i + 1,0}\)\(y_{i,1}\) 各不相同。

\(x_{st} < p_i < x_{ed},1 ≤ a,b,c ≤ 10^3\)

\(n,k\leq 100,000\),交点数\(\leq 500,000\)

\(\\\)

\(c\)对答案的贡献可以旋转坐标系过后扫描线解决。

考虑最大和最小的答案一定是其中一个最大化\(a\)的数量,另外一个最小化\(a\)的数量。\(a\)的最大值就是逆序对(交点)个数(虽然为啥我也不知道);最小值很显然,将这个序列看做一个置换,那么答案就是\(n-\)循环节个数。

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 500005
#define eps 1e-9using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}int n;
ll a,b,c,st,ed;
int k;
ll Y0[N],Y1[N];
ll x[N],y[N];
long double d[N];
int rk[N],t[N];
bool cmp(int a,int b) {return Y1[a]<Y1[b];}
struct point {long double x,y;point() {}point(long double _x,long double _y) {x=_x,y=_y;}bool operator <(const point &a)const {if(fabs(x-a.x)>1e-7) return x<a.x;return y<a.y;}
}p[N];
int ptot;
void Get_point(int a,int b) {long double L=abs(Y0[a]-Y0[b]),R=abs(Y1[a]-Y1[b]);long double K=L/(L+R);long double x=1.0*st+(ed-st)*K,y=1.0*Y0[a]+(Y1[a]-Y0[a])*K;p[++ptot]=point(x-y,x+y);
}struct Line {double x;int y1,y2,flag;Line() {}Line(double _x,int _y1,int _y2,int _flag) {x=_x,y1=_y1,y2=_y2,flag=_flag;}bool operator <(const Line &a)const {if(fabs(a.x-x)>eps) return x<a.x;return flag<a.flag;}
}L[N<<2];
int ltot;
int cal1() {static bool vis[N];int cnt=0;for(int i=1;i<=n;i++) {if(vis[i]) continue ;cnt++;for(int j=i;!vis[j];j=rk[j]) vis[j]=1;}return cnt;
}ll ans0,ans1;
int low(int i) {return i&(-i);}
int tem[N<<3];
int m;
void add(int v,int f) {for(int i=v;i<=m;i+=low(i)) tem[i]+=f;}
void add(int l,int r,int f) {add(l,f),add(r+1,-f);}
int query(int v) {int ans=0;for(int i=v;i;i-=low(i)) ans+=tem[i];return ans;
}
void discrete() {static long double py[N<<3];static int ty;ty=0;for(int i=1;i<=ptot;i++) py[++ty]=p[i].y;for(int i=1;i<=k;i++) py[++ty]=y[i]+d[i],py[++ty]=y[i]-d[i];sort(py+1,py+1+ty);int dy=unique(py+1,py+1+ty)-py-1;m=dy;for(int i=1;i<=ptot;i++) {L[++ltot]=Line(p[i].x,lower_bound(py+1,py+1+dy,p[i].y)-py,0,1);if(fabs(py[L[ltot].y1]-p[i].y)>eps) exit(-1);}for(int i=1;i<=k;i++) {int y1=lower_bound(py+1,py+1+dy,y[i]-d[i])-py,y2=lower_bound(py+1,py+1+dy,y[i]+d[i])-py;L[++ltot]=Line(x[i]-d[i],y1,y2,0);L[++ltot]=Line(x[i]+d[i],y1,y2,3);}
}int cal2() {sort(L+1,L+1+ltot);int ans=0;for(int i=1;i<=ltot;i++) {if(L[i].flag==0) {add(L[i].y1,L[i].y2,1);} else if(L[i].flag==1) {if(query(L[i].y1)) ans++;} else {add(L[i].y1,L[i].y2,-1);}}return ans;
}
int main() {n=Get(),a=Get(),b=Get(),c=Get(),st=Get(),ed=Get();for(int i=1;i<=n;i++) Y0[i]=Get();for(int i=1;i<=n;i++) Y1[i]=Get();for(int i=1;i<=n;i++) t[i]=i;sort(t+1,t+1+n,cmp);for(int i=1;i<=n;i++) rk[t[i]]=i;for(int i=1;i<=n;i++) t[i]=0;for(int i=1;i<=n;i++) {t[i]=i;int j=i;while(j>1&&rk[t[j-1]]>rk[t[j]]) {Get_point(t[j-1],t[j]);swap(t[j-1],t[j]);j--;}}sort(p+1,p+1+ptot);k=Get();for(int i=1;i<=k;i++) {x[i]=Get(),y[i]=Get(),d[i]=Get();ll X=x[i]-y[i],Y=x[i]+y[i];x[i]=X,y[i]=Y;}ll cnt=n-cal1();ans0=cnt*a+(ptot-cnt)*b;ans1=ptot*a;ll sp=0;for(int i=1;i<=ptot;i++) {long double X=p[i].x-p[i].y,Y=p[i].x+p[i].y;for(int j=1;j<=k;j++) {if(fabs(p[i].x-1.0*x[j])<=d[j]&&fabs(p[i].y-1.0*y[j])<=d[j]) {sp++;break;}}}discrete();int watch=cal2();ans0+=watch*c,ans1+=watch*c;if(ans0>ans1) swap(ans0,ans1);cout<<ans0<<" "<<ans1;return 0;
}

转载于:https://www.cnblogs.com/hchhch233/p/10864819.html

这篇关于Loj #3085. 「GXOI / GZOI2019」特技飞行的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/418491

相关文章

loj 最小生成树(模板)

最小生成树 模板如下 kruskal算法 #include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int maxn=2e5+10;typedef long long ll;ll ans=0;int f[maxn],n,m;struct node{int x,y,z;}s[m

【loj P4570】: 元素 线性基

传送门 分析 首先我们需要知道一个性质,线性基内的元素数量是唯一的,也就是说我们能够插入的数的个数是确定的,如果有一个数不能插入线性基,我们只需要更改插入顺序就可以了 所以,我们可以贪心的去想,按照魔力值从大到小的顺序把元素需要插入线性基,能够插入就加上这个矿石的魔力值 代码 #pragma GCC optimize(3)#include <bits/stdc++.h>#define

【LOJ】白雪皑皑 并查集

传送⻔ 分析 因为区间会被后面的区间覆盖,所以考虑从后往前处理 我们用 f [ i ] f[i] f[i]表示 i i i节点前第一个没有被染色的节点,然后用并查集进行维护即可 代码 #include <bits/stdc++.h>#define debug(x) cout<<#x<<":"<<x<<endl;#define dl(x) printf("%lld\n",x);#def

LOJ#2473. 「九省联考 2018」秘密袭击(线段树合并+拉格朗日插值)

一个非常强的题。 也许比较套路但是都比较生疏。 主要使用两个思想。 首先是把求第k大的权转化成枚举i 从1 - W 计算 最终的第k大 大于等于 i 的和。 然后就可以 转化成一个DP。 f[i][j][k] represents the subtree of the node i and we are considering the value of the kth node is not le

Loj#139 树链剖分

题目链接 问题分析 一道比较标准的模板题。唯一需要考虑的是换根操作。 发现换根对链上的操作并没有影响,考虑对树上以\(u\)为根子树的影响。设原树上以\(u\)为根的子树是\(T\)。如果新的根在\(T\)的外部,那么以\(u\)为根的子树不变。如果新根就是\(u\),那么子树就是整棵树。否则,取原树中\(u\)的一个儿子\(v\),\(v\)包含新的根,那么新的以\(u\)为根的子树就是整棵树

LOJ #2483 [CEOI2017]Building Bridges CDQ分治+斜率优化

题目链接:传送门 洛咕传送门 令 s u m w sumw sumw表示 w w w的前缀和。 显然的 d p dp dp方程: d p [ i ] = m i n ( d p [ j ] + ( h [ i ] − h [ j ] ) 2 + s u m w [ i − 1 ] − s u m w [ j ] ) dp[i]=min(dp[j]+(h[i]-h[j])^2+sumw[i-1]-

Leetcode 3085. Minimum Deletions to Make String K-Special

Leetcode 3085. Minimum Deletions to Make String K-Special 1. 解题思路2. 代码实现 题目链接:3085. Minimum Deletions to Make String K-Special 1. 解题思路 这一题思路上来说的话我们只需要统计一下word当中所有的字符出现的频次,然后依次排序,我们只需要考察各个删除方案使得所有存在

[LOJ 5516]无聊的数对

无聊的数对 题解 好水的题呀,为什么还是这句话??? 额,首先,我们知道要使得的__builtin_parityll(即它在二进制下1的个数是否为奇,一下简称parityll为奇的话,a与b的parityll一定是不同的。 这,还是证一下吧。 我们设有个1,有个1,它们共有的1的个数为,那么它们异或后的1的个数为,它的奇偶性与是相同的,所以要使得的1个数为奇,必定为奇,于是与的奇偶性不同

LOJ#6032. 「雅礼集训 2017 Day2」水箱【笛卡尔树】

题目描述: 题目分析: 如果想象水慢慢往上涨,高的隔板会将不同的区域分隔开,导致两边的水位高低可能不一样。 而水位如果超过了隔板,那么这个隔板两边就等价了。 于是我们想到用最大值将区间划分,然后答案就可以这么求(设当前隔板的高度为h,最近的比当前隔板高的隔板的高度为h’): 如果水位没有达到当前隔板,可以满足的条件为h到h’中无水的条件加上当前隔板两边水位任意时最多满足的条件。 如果水位

LOJ #2542 [PKUWC2018]随机游走 (概率期望、组合数学、子集和变换、Min-Max容斥)

很好很有趣很神仙的题! 题目链接: https://loj.ac/problem/2542 题意: 请自行阅读 题解首先我们显然要求的是几个随机变量的最大值的期望(不是期望的最大值),然后这玩意很难求,根据Min-Max容斥化成最小值的期望来求。 Minn-max容斥是指\(\max(x_1,x_2,...,x_n)=\sum_{S\in \{1,2,...,n\} } (-1)^{|S|-1}