怎么一眼看出该题是否用二分呢?一般题目要求中出现以下关键词:最大值最小、最小值最大、满足条件的最小/最大、单调序列查找、分组、猜答案等类似词汇,直接选择二分。
一、万能通用模板
1.1查找某个值是否存在
python
def binary_search(arr, target):
l, r = 0, len(arr)-1
while l <= r:
mid = (l + r) // 2
if arr[mid] == target:
return mid # 找到
elif arr[mid] < target:
l = mid + 1
else:
r = mid - 1
return -1 # 没找到
1.2答案二分
适用于求最小满足条件的值
python
def check(x):
# 判断 x 是否满足题目条件
return True/False
def find():
l = 最小可能
r = 最大可能
ans = r
while l <= r:
mid = (l + r) // 2
if check(mid):
ans = mid
r = mid - 1 # 想更小
else:
l = mid + 1 # 需要更大
return ans
例题
问题描述
输入描述
输出描述
输出切出的正方形巧克力最大可能的边长。
输入输出示例
输入
2 10
6 5
5 6
输出
2
python
# 变量:K位小朋友、N块巧克力、巧克力高为H、宽为W
# 要求:N块切出K块正方形大小相同的巧克力(当分出的巧克力块数大于等于小朋友人数满女足条件)
# 求满足条件的最大的边长
# 分成边长为n的巧克力
def bian(n):
# 未分前有n块巧克力
ans=0
for i in range(N):
# 每块大巧克力分出的小巧克力的总和
ans+=(H[i]//n)*(W[i]//n)
# ans+=min(H[i]//n,W[i]//n)
# 看是否满足分给的人数
if ans>=K:
return True
return False
# 接取数据N、K
N,K=map(int,input().split())
H=[]
W=[]
# 分别借出数据H、W
for i in range(N):
a=list(map(int,input().split()))
H.append(a[0])
W.append(a[1])
# 二分查找遍历边
# 左开右闭
left=1
right=100000
# 区间不为空
while left<right:
# 这个中间值就是要分成的边长n
mid=(left+right)//2
# 如果可以分成mid块巧克力,目标是分的更大
if bian(mid):
left=mid+1# [mid+1,right)
else:
right=mid# [left,mid)
# 最终结果target[left,right)
print(left-1)
例题
输入描述
输出描述
输出一个整数表示答案。
输入输出样例
输入
10 3
5
2
10
输出
6
python
# N个方格、K台机器人、第i台在第Ai个放个区域中
N,K=map(int,input().split())
# 首先塞一个0,数组遍历是从1开始的
A=[0]
for i in range(K):
A.append(int(input()))
A.sort()
def check(mid):
pos=0# 表示区域1~pos已被清扫,区域pos+1~n未被清扫
# 遍历每一个机器人
for i in range(1,K+1):
# 花费这么多时间够不够
time=mid
# 1.往左清扫
if pos<A[i]:
time-=2*(A[i]-pos-1) # 往左清扫需要花费2*(a[i]-pos-1)
# 如果时间小于 0,说明无法清扫完左边的区域,时间不够
if time<0:
return False
# 2.往右清扫+每个机器人打扫完更新pos
pos=A[i]+time//2# 如果还有剩余时间,往右清扫
return pos>=N
left=1
right=2*N
# 左开右闭
while left<right:
mid=(left+right)//2
if check(mid):
right=mid
else:
left=mid+1
# [left,right)
# [target)
print(right)



