跳到主要内容
原文378 词数2 分钟

题解:P8665 [蓝桥杯 2018 省 A] 航班时间

概述

给出往返航班的起飞与降落时刻(可能跨天),两地存在时差,求实际飞行时间。设飞行时间为 x、时差为 k,去程耗时为 x+k、回程耗时为 x-k,两式相加消去时差,飞行时间即去程与回程耗时的平均值。实现上把时刻统一折算成总秒数相减得到两段耗时,取平均后再还原为时分秒,用 scanf 配合 getchar 处理可能出现的跨天括号。时间复杂度线性于询问数。

参考资料​

解题思路​

时差​

显然:

去程时间=飞行时间+时差回程时间=飞行时间−时差\begin{aligned} \text{去程时间}=\text{飞行时间}+\text{时差} \\ \text{回程时间}=\text{飞行时间}-\text{时差} \end{aligned}

设飞行时间为 xx,去程时间为 t1t_1,回程时间为 t2t_2,时差为 kk,则有:

{t1=x+kt2=x−k\begin{cases} t_1=x+k \\ t_2=x-k \end{cases}

两式相加得:

t1+t2=2x  ⟹  x=t1+t22t_1+t_2=2x\implies x=\frac{t_1+t_2}{2}

不难发现,飞行时间 xx 为去程时间 t1t_1 与回程时间 t2t_2 的平均值。

输入​

使用 scanf 读入前半部分的时间:

51 Bcpp
scanf("%d:%d:%d %d:%d:%d",&h1,&m1,&s1,&h2,&m2,&s2);

若有后半部分的额外天数,两部分之间会存在空格,所以可以用 getchar 判断下一个字符是否为空格:

36 Bcpp
if(getchar()==' ')scanf("(+%d)",&d);

为便于计算,将时间统一转化为总秒数:

t=86400d+3600h+60m+st=86400d+3600h+60m+s

计算​

分别用 降落时间 减去 起飞时间,求出 去程时间 和 回程时间,计算两者的平均值。

输出​

将总秒数还原为时分秒,设时分秒分别为 h,m,sh,m,s,显然:

t=3600h+60m+st=3600h+60m+s

因为 3600h3600h 和 60m60m 都是 6060 的倍数,所以:

s=t mod 60s=t\bmod 60

因为 3600h3600h 是 36003600 的倍数,而 0≤s<600\le s<60,所以:

m≤t mod 360060<m+1  ⟹  m=⌊t mod 360060⌋m\le\frac{t\bmod 3600}{60}<m+1\implies m=\left\lfloor\frac{t\bmod 3600}{60}\right\rfloor

因为 0≤s,m<60  ⟹  0≤60m+s<36000\le s,m<60\implies 0\le60m+s<3600,所以:

h≤t3600<h+1  ⟹  h=⌊t3600⌋h\le\frac{t}{3600}<h+1\implies h=\left\lfloor\frac{t}{3600}\right\rfloor

使用 printf 格式化输出时间:

55 Bcpp
printf("%02d:%02d:%02d\n",ans/3600,ans%3600/60,ans%60);

参考代码​

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

int get()
{
int h1,m1,s1,h2,m2,s2,d=0;
scanf("%d:%d:%d %d:%d:%d",&h1,&m1,&s1,&h2,&m2,&s2);
if(getchar()==' ')scanf("(+%d)",&d);
return (d*86400+h2*3600+m2*60+s2)-(h1*3600+m1*60+s1);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int ans=get()+get()>>1;
printf("%02d:%02d:%02d\n",ans/3600,ans%3600/60,ans%60);
}
return 0;
}