热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

YBT高效进阶4.6.2洛谷P1081开车旅行(最详细)

YBT高效进阶4.6.2洛谷P1081开车旅行TITLE题目描述小A和小B决定利用假期外出旅行,他们将想去的城市从1到n编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的




YBT高效进阶 4.6.2 洛谷P1081 开车旅行
TITLE

题目描述

小A和小B决定利用假期外出旅行,他们将想去的城市从1到n编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市i的海拔高度为h_i城市i和城市j之间的距离d_{i,j},恰好是这两个城市海拔高度之差的绝对值,即





d



i


,


j




=






h


i







h


j







d_{i,j}=|h_i-h_j|


di,j​=∣hi​−hj​∣
旅行过程中,小A和小B轮流开车,第一天小A开车,之后每天轮换一次。他们计划选择一个城市s作为起点,一直向东行驶,并且最多行驶x公里就结束旅行。
小 A 和小B的驾驶风格不同,小B 总是沿着前进方向选择一个最近的城市作为目的地,而小A 总是沿着前进方向选择第二近的城市作为目的地(注意:本题中如果当前城市到两个城市的距离相同,则认为离海拔低的那个城市更近)。如果其中任何一人无法按照自己的原则选择目的城市,或者到达目的地会使行驶的总距离超出 x 公里,他们就会结束旅行。

在启程之前,小 A 想知道两个问题:

1、 对于一个给定的




x


=



x


0




x=x_0


x=x0​,从哪一个城市出发,小 A 开车行驶的路程总数与小B 行驶的路程总数的比值最小(如果小 B 的行驶路程为 0,此时的比值可视为无穷大,且两个无穷大视为相等)。如果从多个城市出发,小A 开车行驶的路程总数与小 B 行驶的路程总数的比值都最小,则输出海拔最高的那个城市。

2、对任意给定的




x


=



x


i



















s


i




x=x_i和出发城市s_i


x=xi​和出发城市si​小 \text{A}A 开车行驶的路程总数以及小 \text BB 行驶的路程总数。


输入格式

第一行包含一个整数 n,表示城市的数目。

第二行有 n个整数,每两个整数之间用一个空格隔开,依次表示城市 1 到城市 n 的海拔高度,即





h


1



,



h


2



.


.


.



h


n




h_1,h_2 ... h_n


h1​,h2​...hn​ ,且每个





h


i




h_i


hi​ 都是互不相同的。

第三行包含一个整数





x


0




x_0


x0​

第四行为一个整数 m,表示给定 m 组





s


i







x


i



x



s_i和x_ix


si​和xi​x

接下来的 m 行,每行包含 2 个整数





s


i







x


i




s_i和x_i


si​和xi​ ,表示从城市





s


i




s_i


si​ 出发,最多行驶





x


i




x_i


xi​ 公里。


输出格式

输出共 m+1 行。

第一行包含一个整数





s


0




s_0


s0​,表示对于给定的





x


0




x_0


x0​,从编号为





s


0




s_0


s0​ 的城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值最小。

接下来的 m 行,每行包含 2 个整数,之间用一个空格隔开,依次表示在给定的





s


i







x


i




s_i和x_i


si​和xi​ 下小 A 行驶的里程总数和小 B 行驶的里程总数。


输入输出样例


输入 #1复制

4
2 3 1 4
3
4
1 3
2 3
3 3
4 3

输出 #1复制

1
1 1
2 0
0 0
0 0

输入 #2复制

10
4 5 6 1 2 3 7 8 9 10
7
10
1 7
2 7
3 7
4 7
5 7
6 7
7 7
8 7
9 7
10 7

输出 #2复制

2
3 2
2 4
2 1
2 4
5 1
5 1
2 1
2 0
0 0
0 0

说明/提示


【样例1说明】

在这里插入图片描述

各个城市的海拔高度以及两个城市间的距离如上图所示。

如果从城市 1 出发,可以到达的城市为 2,3,4,这几个城市与城市 1 的距离分别为 1,1,2,但是由于城市 3 的海拔高度低于城市 2,所以我们认为城市 3 离城市 1 最近,城市2 离城市 1 第二近,所以小A会走到城市 2。到达城市 2 后,前面可以到达的城市为 3,4,这两个城市与城市2 的距离分别为 2,1,所以城市 4 离城市 2 最近,因此小B会走到城市4。到达城市 4 后,前面已没有可到达的城市,所以旅行结束。

如果从城市 2 出发,可以到达的城市为 3,4,这两个城市与城市 22 的距离分别为 2,1,由于城市 3 离城市 2 第二近,所以小 A 会走到城市 3。到达城市 3 后,前面尚未旅行的城市为 4,所以城市 4 离城市 3 最近,但是如果要到达城市 4,则总路程为 2+3=5>3,所以小 B 会直接在城市 3 结束旅行。

如果从城市 33 出发,可以到达的城市为 44,由于没有离城市 33 第二近的城市,因此旅行还未开始就结束了。

如果从城市 44 出发,没有可以到达的城市,因此旅行还未开始就结束了。


【样例2说明】

当 x=7时,如果从城市 1 出发,则路线为 1→2→3→8→9,小 A 走的距离为 1+2=3,小B 走的距离为 1+1=2。(在城市 1 时,距离小A 最近的城市是 2 和 6,但是城市 2 的海拔更高,视为与城市 1 第二近的城市,所以小A 最终选择城市 2;走到9 后,小A 只有城市 10 可以走,没有第二选择可以选,所以没法做出选择,结束旅行)

如果从城市 2 出发,则路线为 2→6→7,小 A 和小 B 走的距离分别为 2,4。

如果从城市 3 出发,则路线为 3→8→9,小 A 和小B 走的距离分别为2,1。

如果从城市 4 出发,则路线为 4→6→7,小 A 和小 B 走的距离分别为 2,4。

如果从城市 5 出发,则路线为 5→7→8,小 A 和小B 走的距离分别为 5,1。

如果从城市 6 出发,则路线为6→8→9,小A 和小 B 走的距离分别为5,1。

如果从城市 7 出发,则路线为 7→9→10,小 A 和小 B 走的距离分别为2,1。

如果从城市 8 出发,则路线为8→10,小A 和小B 走的距离分别为2,0。

如果从城市 9 出发,则路线为 9,小A 和小 B 走的距离分别为 0,0(旅行一开始就结束了)。

如果从城市 10 出发,则路线为 10,小A 和小B 走的距离分别为0,0。

从城市 2 或者城市 4 出发小 A 行驶的路程总数与小 B 行驶的路程总数的比值都最小,但是城市 2的海拔更高,所以输出第一行为 2。


【数据范围与约定】












30


%

















1





n





20


,


1





m





20






对于 30\%的数据,有1\le n \le 20,1\le m\le 20;


对于30%的数据,有1≤n≤20,1≤m≤20;











40


%

















1





n





100


,


1





m





100






对于40\%的数据,有1\le n \le 100,1\le m\le 100;


对于40%的数据,有1≤n≤100,1≤m≤100;











50


%

















1





n





100


,


1





m





1000






对于 50\%的数据,有1\le n \le 100,1\le m\le 1000;


对于50%的数据,有1≤n≤100,1≤m≤1000;











70


%

















1





n





1000


,


1





m





1



0


4




对于 70\%的数据,有1\le n \le 1000,1\le m\le 10^4


对于70%的数据,有1≤n≤1000,1≤m≤104








100


%














1





n


,


m





1



0


5



,





1



0


9







h


i






1



0


9



,


1






s


i






n


,


0






x


i






1



0


9



















h


i






















于 100\%的数据:1\le n,m \le 10^5,-10^9 \le h_i≤10^9,1 \le s_i \le n,0 \le x_i \le 10^9,数据保证 h_i​互不相同。


于100%的数据:1≤n,m≤105,−109≤hi​≤109,1≤si​≤n,0≤xi​≤109,数据保证hi​​互不相同。


SOLUTION

记得开long long
YBT高效进阶,这是我最后做的一题,这题我做了整整半天多


两点间找最优点

先比较距离
若距离都为INF,无解
若距离相当,判海拔,
若距离不相等,判距离
不要忘记判断无解(没有最优点)

if(dx==INF&&dy==INF)return 0;//无解

我因为漏了这句,调了两个多小时

long long cmp(long long x,long long y,long long dx,long long dy)//两个点找最优,x,y点id,dx,dy到正在找的点的距离
{
if(dx==INF&&dy==INF)return 0;//无解
if(dx==dy)//距离相等
{
if(h[x] return y;
}
if(dx return y;
}

小A目的地计算

因为排好了序,要找周围4个点的次优值
先算出周围两个点的最优点
判4个点时,不能是最优点
再剩下的点里找最优点
可以分治,先找左边,再找右边,再合并
注意判点是否存在
注意要判断找到的点是否存在

if(lw)dislw=abs(h[lw]-h[x]);//计算距离
if(rw)disrw=abs(h[rw]-h[x]);

我因为漏了这两句,调了一个多小时

long long cmp_four(long long x)
{
long long ld,rd,lld,rrd,lw,rw,dislw,disrw,w=cmp_two(x);
ld=lld=rd=rrd=dislw=disrw=INF;
if(l[x]&&l[x]!=w)ld=abs(h[x]-h[l[x]]);//不为最小值,计算左右距离
if(r[x]&&r[x]!=w)rd=abs(h[x]-h[r[x]]);
if(l[l[x]])lld=abs(h[l[l[x]]]-h[x]);
if(r[r[x]])rrd=abs(h[r[r[x]]]-h[x]);
lw=cmp(l[l[x]],l[x],lld,ld);//计算左边2个点的最优位置
rw=cmp(r[r[x]],r[x],rrd,rd);//计算右边2个点的最优位置
if(lw)dislw=abs(h[lw]-h[x]);//计算距离
if(rw)disrw=abs(h[rw]-h[x]);
return cmp(lw,rw,dislw,disrw);//计算最优点
}

小B目的地计算

因为排好了序,找周围两个点的最优点
注意判点是否存在

long long cmp_two(long long x)
{
long long disl=INF,disr=INF;
if(l[x])disl=abs(h[l[x]]-h[x]);//计算左右距离
if(r[x])disr=abs(h[r[x]]-h[x]);
return cmp(l[x],r[x],disl,disr);
}

预处理

预处理出从任意一个点出发,A\B走一步的目的点及路程

题目要求:
1.AB不同的驾驶风格
A走次近点
B走最近点
2.一直从西往东走

为了满足1,先排序,
最近点在周围2个点中
次近点在周围4个点中

为了满足2,用双向链表
先按排序后的顺序建表
最近点:l[x],r[x]
次近点:l[l[x]],l[x],r[x],r[r[x]]
从编号小的点枚举到编号大的点(自西先东)
每次计算完一个点
就把当前点删除
以后就无法访问该点
保证一直向东开

void work()
{
long long i;
sort(city+1,city+1+n,sortcmp);//排序
for(i=1; i<=n; ++i)l[city[i].id]=city[i-1].id,r[city[i].id]=city[i+1].id;//双向链表
for(i=1; i<=n; ++i)
{
fb[i]=cmp_two(i);//左右找最小
disb[i][0]=abs(h[i]-h[fb[i]]);
fa[i][0]=cmp_four(i);//周围四个找次小
disa[i][0]=abs(h[i]-h[fa[i][0]]);
if(l[i])r[l[i]]=r[i];//删除当前点
if(r[i])l[r[i]]=l[i];//保证一直向东走
}
return;
}

DP


fa[i][j]表示从i出发走2j步的目的点(不论AB谁走)
fb[i]表示B从i出发走1步的目的点
disa[i][j]表示从i走2^j步过程中A走的路程
disb[i][j]表示从i走2^j步过程中B走的路程
用倍增优化,计算出值

void DP()
{
long long i,j;
for(i=1; i<=n; i++)//预处理AB各走一次的值
{
fa[i][1]=fb[fa[i][0]];//fa[i][j]表示从i走2^j步到达的点(不管AB走)
disa[i][1]=disa[i][0];//disa[i][j]表示从i走2^j步过程中A走的路程
disb[i][1]=disb[fa[i][0]][0];//disb[i][j]表示从i走2^j步过程中B走的路程
}
for(j=2; j<=mxm; ++j)//根据预处理,计算AB走2^j次的值
for(i=1; i<=n; ++i)//倍增
{
fa[i][j]=fa[fa[i][j-1]][j-1];
disa[i][j]=disa[i][j-1]+disa[fa[i][j-1]][j-1];
disb[i][j]=disb[i][j-1]+disb[fa[i][j-1]][j-1];
}
return;
}

用倍增计算出AB走的路程

先求出AB一起可以走多远(AB交替走,AB走的次数相同)
最后特判,如果A还能再走一次,A就再走一次

pair solve(long long s,long long x)
{
long long i;
pair ans;
for(ans.first=ans.secOnd=0,i=mxm; i; --i)//倍增求解
if(fa[s][i]&&disa[s][i]+disb[s][i]+ans.first+ans.second<=x)//能走且距离<=x
ans.first+=disa[s][i],ans.second+=disb[s][i],s=fa[s][i];//更新AB路程
if(fa[s][0]&&ans.first+ans.second+disa[s][0]<=x)ans.first+=disa[s][0];//若A还能走,再走一次
return ans;
}

第一问:

枚举从每个点出发
分别用倍增计算出A,B走的路程
和当前最优值比较,更新答案和当前最优值

void solve_begin()
{
long long ans=0,i;
pair sol,mn;
for(mn.first=1,mn.secOnd=0,i=1; i<=n; ++i)//枚举从每个点出发
{
sol=solve(i,x0);//计算两人路程
if(sol.second&&((sol.first*mn.secOnd==sol.second*mn.first&&h[ans] mn=sol,ans=i;
}
printf("%lld\n",ans);
return;
}

第二问:

输入询问,计算答案,输出答案
用倍增计算出A,B走的路程

void solve_end()
{
long long m,i,x,y;
pair sol;
for(scanf("%lld",&m),i=1; i<=m; ++i)scanf("%lld%lld",&x,&y),sol=solve(x,y),printf("%lld %lld\n",sol.first,sol.second);//输入询问,计算答案,输出答案
return;
}

CODE

//Before nobody understood the code
#include
#include
#include
#include
#include
using namespace std;
const long long mxn=100000,mxm=30,INF=0x7f7f7f7f;
long long n,x0,h[mxn+10],disa[mxn+10][mxm+10],disb[mxn+10][mxm+10],fa[mxn+10][mxm+10],fb[mxn+10],l[mxn+10],r[mxn+10];
struct CITY
{
long long id,h;
} city[mxn+10];
void input()//输入
{
long long i;
for(scanf("%lld",&n),i=1; i<=n; ++i)scanf("%lld",&h[i]),city[i].id=i,city[i].h=h[i];
scanf("%lld",&x0);
return;
}
bool sortcmp(CITY a,CITY b)
{
return a.h}
long long cmp(long long x,long long y,long long dx,long long dy)//两个点找最优,x,y点id,dx,dy到正在找的点的距离
{
if(dx==INF&&dy==INF)return 0;//无解
if(dx==dy)//距离相等
{
if(h[x] return y;
}
if(dx return y;
}
long long cmp_two(long long x)
{
long long disl=INF,disr=INF;
if(l[x])disl=abs(h[l[x]]-h[x]);//计算左右距离
if(r[x])disr=abs(h[r[x]]-h[x]);
return cmp(l[x],r[x],disl,disr);
}
long long cmp_four(long long x)
{
long long ld,rd,lld,rrd,lw,rw,dislw,disrw,w=cmp_two(x);
ld=lld=rd=rrd=dislw=disrw=INF;
if(l[x]&&l[x]!=w)ld=abs(h[x]-h[l[x]]);//不为最小值,计算左右距离
if(r[x]&&r[x]!=w)rd=abs(h[x]-h[r[x]]);
if(l[l[x]])lld=abs(h[l[l[x]]]-h[x]);
if(r[r[x]])rrd=abs(h[r[r[x]]]-h[x]);
lw=cmp(l[l[x]],l[x],lld,ld);//计算左边2个点的最优位置
rw=cmp(r[r[x]],r[x],rrd,rd);//计算右边2个点的最优位置
if(lw)dislw=abs(h[lw]-h[x]);//计算距离
if(rw)disrw=abs(h[rw]-h[x]);
return cmp(lw,rw,dislw,disrw);//计算最优点
}
void work()
{
long long i;
sort(city+1,city+1+n,sortcmp);//排序
for(i=1; i<=n; ++i)l[city[i].id]=city[i-1].id,r[city[i].id]=city[i+1].id;//双向链表
for(i=1; i<=n; ++i)
{
fb[i]=cmp_two(i);//左右找最小
disb[i][0]=abs(h[i]-h[fb[i]]);
fa[i][0]=cmp_four(i);//周围四个找次小
disa[i][0]=abs(h[i]-h[fa[i][0]]);
if(l[i])r[l[i]]=r[i];//删除当前点
if(r[i])l[r[i]]=l[i];//保证一直向东走
}
return;
}
void DP()
{
long long i,j;
for(i=1; i<=n; i++)//预处理AB各走一次的值
{
fa[i][1]=fb[fa[i][0]];//fa[i][j]表示从i走2^j步到达的点(不管AB走)
disa[i][1]=disa[i][0];//disa[i][j]表示从i走2^j步过程中A走的路程
disb[i][1]=disb[fa[i][0]][0];//disb[i][j]表示从i走2^j步过程中B走的路程
}
for(j=2; j<=mxm; ++j)//根据预处理,计算AB走2^j次的值
for(i=1; i<=n; ++i)//倍增
{
fa[i][j]=fa[fa[i][j-1]][j-1];
disa[i][j]=disa[i][j-1]+disa[fa[i][j-1]][j-1];
disb[i][j]=disb[i][j-1]+disb[fa[i][j-1]][j-1];
}
return;
}
pair solve(long long s,long long x)
{
long long i;
pair ans;
for(ans.first=ans.secOnd=0,i=mxm; i; --i)//倍增求解
if(fa[s][i]&&disa[s][i]+disb[s][i]+ans.first+ans.second<=x)//能走且距离<=x
ans.first+=disa[s][i],ans.second+=disb[s][i],s=fa[s][i];//更新AB路程
if(fa[s][0]&&ans.first+ans.second+disa[s][0]<=x)ans.first+=disa[s][0];//若A还能走,再走一次
return ans;
}
void solve_begin()
{
long long ans=0,i;
pair sol,mn;
for(mn.first=1,mn.secOnd=0,i=1; i<=n; ++i)//枚举从每个点出发
{
sol=solve(i,x0);//计算两人路程
if(sol.second&&((sol.first*mn.secOnd==sol.second*mn.first&&h[ans] mn=sol,ans=i;
}
printf("%lld\n",ans);
return;
}
void solve_end()
{
long long m,i,x,y;
pair sol;
for(scanf("%lld",&m),i=1; i<=m; ++i)scanf("%lld%lld",&x,&y),sol=solve(x,y),printf("%lld %lld\n",sol.first,sol.second);//输入询问,计算答案,输出答案
return;
}
int main()
{
input(),work(),DP(),solve_begin(),solve_end();
return 0;
}
//Now,everybody understands the code.


推荐阅读
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 解决java.lang.IllegalStateException: ApplicationEventMulticaster not initialized错误的方法和原因
    本文介绍了解决java.lang.IllegalStateException: ApplicationEventMulticaster not initialized错误的方法和原因。其中包括修改包名、解决service name重复、处理jar包冲突和添加maven依赖等解决方案。同时推荐了一个人工智能学习网站,该网站内容通俗易懂,风趣幽默,值得一看。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • Gitlab接入公司内部单点登录的安装和配置教程
    本文介绍了如何将公司内部的Gitlab系统接入单点登录服务,并提供了安装和配置的详细教程。通过使用oauth2协议,将原有的各子系统的独立登录统一迁移至单点登录。文章包括Gitlab的安装环境、版本号、编辑配置文件的步骤,并解决了在迁移过程中可能遇到的问题。 ... [详细]
  • 本文讨论了如何使用GStreamer来删除H264格式视频文件中的中间部分,而不需要进行重编码。作者提出了使用gst_element_seek(...)函数来实现这个目标的思路,并提到遇到了一个解决不了的BUG。文章还列举了8个解决方案,希望能够得到更好的思路。 ... [详细]
  • 基于移动平台的会展导游系统APP设计与实现的技术介绍与需求分析
    本文介绍了基于移动平台的会展导游系统APP的设计与实现过程。首先,对会展经济和移动互联网的概念进行了简要介绍,并阐述了将会展引入移动互联网的意义。接着,对基础技术进行了介绍,包括百度云开发环境、安卓系统和近场通讯技术。然后,进行了用户需求分析和系统需求分析,并提出了系统界面运行流畅和第三方授权等需求。最后,对系统的概要设计进行了详细阐述,包括系统前端设计和交互与原型设计。本文对基于移动平台的会展导游系统APP的设计与实现提供了技术支持和需求分析。 ... [详细]
  • 本文概述了JNI的原理以及常用方法。JNI提供了一种Java字节码调用C/C++的解决方案,但引用类型不能直接在Native层使用,需要进行类型转化。多维数组(包括二维数组)都是引用类型,需要使用jobjectArray类型来存取其值。此外,由于Java支持函数重载,根据函数名无法找到对应的JNI函数,因此介绍了JNI函数签名信息的解决方案。 ... [详细]
  • 本文介绍了关于Java异常的八大常见问题,包括异常管理的最佳做法、在try块中定义的变量不能用于catch或finally的原因以及为什么Double.parseDouble(null)和Integer.parseInt(null)会抛出不同的异常。同时指出这些问题是由于不同的开发人员开发所导致的,不值得过多思考。 ... [详细]
  • 颜色迁移(reinhard VS welsh)
    不要谈什么天分,运气,你需要的是一个截稿日,以及一个不交稿就能打爆你狗头的人,然后你就会被自己的才华吓到。------ ... [详细]
  • 概述H.323是由ITU制定的通信控制协议,用于在分组交换网中提供多媒体业务。呼叫控制是其中的重要组成部分,它可用来建立点到点的媒体会话和多点间媒体会议 ... [详细]
  • Hello.js 是一个用于连接OAuth2服务的JavascriptRESTFULAPI库,如Go ... [详细]
  • 移动传感器扫描覆盖摘要:关于传感器网络中的地址覆盖问题,已经做过很多尝试。他们通常归为两类,全覆盖和栅栏覆盖,统称为静态覆盖 ... [详细]
  • html结构 ... [详细]
author-avatar
當紅冷萱儿_422
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有