Copa Blue Bridge - tema de dos puntos

La dicotomía se divide en: dicotomía de números reales, preguntas teóricas de dicotomía

 

 Problema dicotómico de rutina: maximizar el valor mínimo y minimizar el valor máximo

El uso de dicotomía satisface las condiciones: acotado, monótono.

1. Dos plantillas bipartitas

Encuentra el primero >=x, mid=(low+high)//2, si no, encuentra el siguiente número más grande que él

a=[0,3,5,7,9,11,13]
# [0,1,2,3,4,5,6]
# low = 0 high =6 mid =3  ----->   low=4  high =6
# low = 4 high =6 mid =5  ----->   low=4  high =5
# low = 4 high =5 mid =4  ----->   low=5  high =5
# break   low=high=5
# 找的是靠右的那一个
low=0
high=len(a)-1
def search(low,high,x):  # 查找的是后一个
    while (low<high):
        mid =(low+high)//2   # (2+3)//2=2  偏左
        if (a[mid]>=x):
            high=mid
        else:
            low=mid+1
    print(a[low])
    print(a[high])
search(low,high,10)  # 查找结果10

 Encuentra el primero <=x, mid=(low+high+1)//2, si no, encuentra el número anterior más pequeño que él

a=[0,3,5,7,9,11,13]
# [0,1,2,3,4,5,6]
# low = 0 high =6 mid =3  ----->   low=3  high =6
# low = 3 high =6 mid =5  ----->   low=3  high =4
# low = 3 high =4 mid =4  ----->   low=4  high =4
# break   low=high=4
# 找的是靠左的那一个
low=0
high=len(a)-1
def search(low,high,x):  # 查找的是前一个
    while (low<high):
        mid =(low+high+1)//2   # (2+3+1)//2=3  偏右
        if (a[mid]<=x):
            low=mid
        else:
            high=mid-1
    print(a[low])
    print(a[high])
search(low,high,10)  # 查找结果10
 

Ejemplo de dicotomía

1. Divide el chocolate (según el significado de la pregunta, se convierte en dos puntos, y los dos puntos encuentran la longitud lateral N)

import os
import sys
 
# 请在此输入您的代码
def check(d):  # 检查蛋糕大小为d是否可分
  num = 0
  for i in range(n):
    num+=(w[i]//d)*(h[i]//d)
  if(num>=k):return True
  else:return False
 
h = [0]*100010
w = [0]*100010
n,k = map(int,input().split())
for i in range(n):  # 读入蛋糕大小
  h[i],w[i] = map(int,input().split())
 
L,R = 1,100010   # 结尾更大防止出现边界问题
while L<R:
   mid=(L+R+1)//2   # 偶数中值为右值 [1,2] -->2  ,没有则取前
   if(check(mid)):
     L=mid
   else:
     R=mid-1
 print(L)
 
#  mid=(L+R)//2    #偶数中值为左值  [1,2] -->1  ,没有则取后
#  if(check(mid)):
#    L=mid+1
#  else:
#    R=mid
#print(L-1)

forma más razonable de escribir

import sys  #设置递归深度
import collections  #队列
import itertools  # 排列组合
import heapq  #小顶堆
import math
sys.setrecursionlimit(300000)
 
n,k = map(int,input().split())
save = [] #存放巧克力
Max=1
for i in range(n):
   temp=list(map(int,input().split()))
   Max=max(max(temp),Max)  # 记录大巧克力边长,之后用于二分
   save.append(temp)
 
 
def check(i):
   count=0
   for a,b in save:
      count+=(a//i)*(b//i)
   if count>=k:
      return True
   else:
      return False
left=1
right=Max
while(left<right):  # 找<=x的第一个
   
   mid=(left+right+1)//2
   #print(left,mid,right)
   #print('-'*40)
   if check(mid):
      left=mid
   else:
      right=mid-1
print(left)
#print(right)
#print(mid)
 
 
'''
2 10
6 5
5 6
测试结果
1 4 6
----------------------------------------
1 2 3
----------------------------------------
2 3 3
----------------------------------------
2
2
3
'''
 

2. Saltar piedras (convertir a dos puntos según el significado de la pregunta, encontrar d para dos puntos)

 

 Comience en la posición i (i = 0), y juzgaré la distancia de mi salto actual cuando salte al siguiente paso. Si la distancia del salto es menor que la mitad de los dos puntos, entonces esta es una piedra ilegal y debería ser eliminado ¿Por qué? Lo que dividimos es la distancia de salto más corta, que ya es la más corta, si la distancia de salto es más corta que la más corta, ¿no sería obviamente ilegal, verdad? ¿Qué hacer después de la eliminación? Primero agregue 1 al contador y luego considere saltar hacia adelante. Mire la siguiente piedra después de quitarla y juzgue la distancia de salto nuevamente. Si la distancia de salto esta vez es más larga que la más corta, entonces este salto es completamente posible. Saltaremos y continuaremos juzgando. Si la distancia de salto es No lo quite si es legal, y continúe esta operación hasta que i = n+1, ¿por qué es n+1? Hay n piedras en medio del río, obviamente el punto final está en n+1. (Tenga cuidado de no considerar n como el punto final aquí. De hecho, debe saltar un paso desde n para llegar al punto final).

import sys
import collections
import itertools
import heapq
sys.setrecursionlimit(300000)



Len,n,m =map(int,input().split())
stone=[]    #石头i和到起点的距离
def check(d):
    num=0   # 可以搬走的数量
    pos=0 # 上一块石头位置
    for i in range(0,n):     # 0 - n-1 作为石头下标,总共n快石头
        if (stone[i]-pos<d): # 可以搬走
            num+=1
        else:  # 不能搬走
            pos=stone[i]

    if num<=m:  # 搬走的数量小于要求值,可以继续增大
        return True
    else:
        return False

for i in range(n):
    t=int(input())
    stone.append(t)
L,R=0,Len
while(L<R):
    mid=(L+R+1)//2
    if check(mid):
        L=mid
    else:
        R=mid-1
print(L)
        

3. Rana cruzando el río (convertido a dos puntos según el significado de la pregunta, es decir, la distancia de salto) 

 

'''
将所有的石头按照区间分类:1步可达的石头,2步可达的石头,,,,显然能通过一步走到,就绝对不通过两步去走
因为石头能被踩的次数是有限的,例如:1,2,3,4,假如最大步长为3,在1的时候,可以一步走到4号石头,但要是
从1走到2,再从2走到4,跟直接从岸上走到2,再从2走到4没有区别,因此,每一次移动,都必须移动到不同标号的区间去
有效的移动只有跨不同区间的移动
步长合法性判断:
对于任意石头i,区间[i,i+x)中的石头可被踩的总数>=2x
证明:
岸,1,2,3,|4,5,6,|7,8,9,岸
按照有效移动理论,在1时,下一步只能走到4去,因此,想要容纳1全部的被踩次数,4号的石头高度应>=1号,而显然,
想要总过河次数>=2x,那么区间[1,3]中石头总高度>=2x,因为出门的第一步必须要有2x次以上,即[1,3]总高度>=2x,
又因4号高度>=1号高度,故区间[2,4]高度之和>=2x,以此类推,可以证明,要想总过河次数>=2x,任一石头编号开始长度为
步长的区间石头总高度之和>=2x


再按照二分法搜索答案,适用二分法的特性:当步长为ans时可满足题目要求,ans+1一定可以满足题目要求
初始解区间[1,n],不断将解区间二分寻找到能够满足题目要求的最小解
'''
import sys
import collections
import itertools
import heapq
sys.setrecursionlimit(300000)


def check(mid):
    for i in range(mid,n):
        if sum[i]-sum[i-mid] <2*x:
            return False
    return True

n,x = map(int,input().split())
h = list(map(int,input().split()))
sum=[0]  # 前缀和下标从1开始
temp=0
for i in range(len(h)):   # 前缀和
    temp=temp+h[i]
    sum.append(temp)
L=0
R=n

while(L<R):
    mid=(L+R)//2
    if check(mid):
        R=mid
    else:
        L=mid+1
print(L)

 4. Resolución de dicotomías de números reales y ecuaciones cúbicas unarias (puntuaciones otorgadas)

import sys  #设置递归深度
import collections  #队列
import itertools  # 排列组合
import heapq  #小顶堆
import math
sys.setrecursionlimit(300000)
 
a,b,c,d = map(float,input().split())
def f(x):
   return x*x*x*a+x*x*b+x*c+d
 
ans=[]
for i in range(-100,100):
   if f(i)==0:
      ans.append(i)
   if f(i)*f(i+1)<0:  # 在(i,i+1)内有根
      l=i;r=i+1
      while(r-l>=0.001):  # 保留精度,2位小数,注意循环条件
         mid=(l+r)/2
         if f(l)*f(mid)<0:
            r=mid
         else:
            l=mid
      ans.append(l)
if f(100)==0:
   ans.append(100)
for i in ans:
   print("{:.2f}".format(i),end=' ')

Supongo que te gusta

Origin blog.csdn.net/weixin_52261094/article/details/130332719
Recomendado
Clasificación