题目描述与示例
题目描述
讨厌鬼有一个数x,他每次操作可以令x = x + 1或x = x - 1
讨厌鬼还有两个区间[l1, r1]和[l2, r2],讨厌鬼想知道,令x同时满足以下条件的最小操作数是多少?
- l1 ≤ x ≤ r1,且x是2的倍数
- l2 ≤ x ≤ r2,且x是3的倍数
请输出这个操作数
输入描述
一行输入五个整数x, l1, r1, l2, r2
1 ≤ x ≤ 10^12
1 ≤ l1 ≤ r1 ≤ 10^12
1 ≤ l2 ≤ r2 ≤ 10^12
输出描述
一行一个整数,表示最小操作数。若不存在这样的操作,输出-1。
示例一
输入
5 4 6 1 9
输出
1
说明
+1把5变成6,满足2个条件
示例二
输入
2 2 4 2 8
输出
-1
时空限制
时间限制: C/C++ 1000MS,其他语言 2000MS
内存限制: C/C++ 256M,其他语言 512M
解题思路
条件转换
数据范围很大,考虑O(1)复杂度的算法。
经过若干次操作之后,x需要同时落在区间[l1, r1]和[l2, r2]中,令l = max(l1, l2),r = min(r1, r2),该条件转化为x最终需要落入区间[l, r]中。
x还需要同时是2和3的倍数,由于2和3互质,故该条件转化为x最终需要是6的倍数。
因此题目可以转化为,在区间[l, r]中找到一个距离x最近的一个6的倍数,这个数和x的差的绝对值就是所求的最小操作数。
分类讨论
在区间[l, r]中找到一个距离x最近的一个6的倍数,一共存在3种情况
- x在区间[l, r]左边,即x < l
- x在区间[l, r]右边,即x > r
- x在区间[l, r]之间,即l <= x <= r
对于情况一,我们需要找到大于等于l的第一个6的倍数a,可以用如下方式得到
a = l + ((6 - l % 6) % 6)
对于情况二,我们需要找到小于等于r的第一个6的倍数b,可以用如下方式得到
b = r - r % 6
- 如果存在a > b,说明区间[l, r]实际上并不包含任何6的倍数,返回-1
- 如果是第一种情况,x落在l的左边,那么a是[l, r]中距离x最近的6的倍数,返回a-x
- 如果是第二种情况,x落在r的右边,那么b是[l, r]中距离x最近的6的倍数,返回x-b
if a > b:
return -1
elif x < l:
return a-x
elif x > r:
return x-b
对于情况三,我们需要找到第一个小于等于x的6的倍数xa以及第一个大于等于x的6的倍数xb。可以用类似于求a和b的方法求得。即
xa = x - x % 6
xb = x + ((6 - x % 6) % 6)
对于xa和xb,也要分别讨论与l和r之间的大小关系,查询xa和xb是否落在区间[l, r]中。
- 如果xa落在l的左边,则xb是距离x最近的6的倍数,返回xb-x
- 如果xb落在r的右边,则xa是距离x最近的6的倍数,返回x-xa
- 如果xa和xb均落在[l,r]中,那么选距离更近的作为答案,返回min(x-xa, xb-x)
if xa < l:
return xb-x
elif xb > r:
return x-xa
else:
return min(x-xa, xb-x)
代码
Python
题目:【模拟】阿里蚂蚁2023秋招-讨厌鬼的区间
作者:闭着眼睛学数理化
算法:模拟/数学
代码有看不懂的地方请直接在群上提问
def help(x, l, r):
a是大于等于l的第一个6的倍数
a = l + ((6 - l % 6) % 6)
b是小于等于r的第一个6的倍数
b = r - r % 6
# 如果a大于b,说明区间中不包含6的倍数,返回-1
if a > b:
return -1
# 以下条件语句中,区间[l, r]中一定包含6的倍数
# 第一种情况,x落在l左边,a是答案
elif x < l:
return a-x
# 第二种情况,x落在r的右边,b是答案
elif x > r:
return x-b
# 第三种情况,x落在区间[l,r]之间
else:
# 需要计算,比x小的第一个6的倍数xa和比x大的第一个6的倍数xb
xa = x - x % 6
xb = x + ((6 - x % 6) % 6)
# 如果xa落在l的左边,则xb是距离x最近的6的倍数
if xa < l:
return xb-x
# 如果xb落在r的右边,则xa是距离x最近的6的倍数
elif xb > r:
return x-xa
else:
# 如果xa和xb均落在[l,r]中,那么选距离更近的作为答案
return min(x-xa, xb-x)
输入5个参数
x, l1, r1, l2, r2 = map(int, input().split())
分别获得l和r
l = max(l1, l2)
r = min(r1, r2)
如果r小于l,那么区间不存在,直接输出-1
if r < l:
print(-1)
否则则调用help计算结果
else:
ans = help(x, l, r)
print(ans)
Java
C++
时空复杂度
时间复杂度:O(1)。
空间复杂度:O(1)。
华为OD算法/大厂面试高频题算法练习冲刺训练
-
华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!
-
课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化
-
每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!
-
60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁
-
可上全网独家的欧弟OJ系统练习华子OD、大厂真题
-
可查看链接 OD算法冲刺训练课程表 & OD真题汇总(持续更新)
-
绿色聊天软件戳
od1336
了解更多