蓝桥杯12-23小白入门赛补题

赛题地址:https://www.lanqiao.cn/oj-contest/newbie-2/

第二题:房顶漏水啦

  1. 思路:直接取长/宽的较大值
  2. 代码:
import os
import sys

# 请在此输入您的代码
n, m = map(int, input().split())
x, y = [0] * m, [0] * m
for i in range(m):
    x[i], y[i] = map(int, input().split())

x.sort()
y.sort()
print(max(x[m - 1] - x[0], y[m - 1] - y[0]) + 1) # 取长/宽的最大值即可

第三题:质数王国

  1. 思路:
    • 先用欧拉筛求质数
    • 然后二分第一个大于等于x的数
    • 若相等,则贡献为0
    • 若不等,则贡献为左或者右侧的移动最小值‘
  2. 代码:
import bisect

# 欧拉筛法,记得开两个数组,一个bool,一个存下质数
N = int(1e5) + 20
primes = [True] * N
arr = []
cnt = 0

for i in range(2, N):
    if primes[i]:
        arr.append(i)
        j = i * 2
        while j < N:
            primes[j] = False
            j += i

n = int(input())
res = 0

for x in list(map(int, input().split())):
    l = bisect.bisect_left(arr, x) # bisect_left找大于等于它的第一个数的下标,不存在则为0
    if arr[l] != x: # 不等于的话,就去比较两边哪个离得更近
        res += min(abs(x - arr[l - 1]), abs(arr[l] - x))

print(res)

第四题:取余

  1. 思路:
    • 首先看到这种夹在区间里的数量题,多半是用前缀和的思想。即后面的减去前面的,即为中间一段的数量。
    • 所以目标转换成了求 f(a, b) <= u,即所有满足前面这个条件的数对(a, b)的数量。
    • 因为是a % b,所以可以考虑枚举b。
    • 对于每个b,它可以把[1, a]分成n段,即 n = a // b。
    • 在一段中每个数取余b就是[1, b - 1],那么每一段就可以统计贡献了,即min(u, b - 1) + 1,为什么要与u取最小值呢,就是那个条件的限制呀。
    • 所以这一部分的贡献就是n * (min(u, b - 1) + 1)
    • 当然并不是a总是均匀分成n段,还会有剩余的一段,它们的贡献很简单是min(u, a % b)
    • 综上,统计每个b的两部分贡献即是答案
  2. 代码:
import os
import sys

# 请在此输入您的代码
def f(a,b,high):
  if high<0:
    return 0
  ans=0
  for i in range(1,b+1):
    n=a//i
    ans+=n*(min(high,i-1)+1)
    ans+=min(high,a%i)
  return ans

a,b,s,t=map(int,input().strip().split())
print(f(a,b,t)-f(a,b,s-1))

第五题:数学尖子生

  1. 思路:
    • 最重要的是看懂f(b) = a这个定义的意思。就是说[1, a - 1]都是b的因子,但是a不是b的因子。比如f(6) = 4
    • 然后题目要求就是给定一个a和n,求[1, n]中有多少个数b满足f(b) = a
    • 其实根据第一步的分析可以很自然的想到容斥定理,就是求[1, a]都为因子的数字的个数,然后减去[1, a - 1]都为因子的个数,即可得到[1, a - 1]都是b的因子,但是a不是b的因子的个数。
    • 其中涉及到一个求[1, n]的最小公倍数的递推式:p[i] = lcm(p[i - 1], i)
  2. 代码:
from math import gcd  # 最大公约数

def my_lcm(a, n):  # 求1 ~ a-1所有数的最小公倍数
    lcm = 1
    for i in range(1, a):
        lcm = lcm * i // gcd(lcm, i)
        if lcm > n:  # 最小公倍数 > b的最大值, 则所有b都不满足
            return 0
    return lcm

# 符合条件的b:不能被a整除但一定能被1,2,3...a-1每一个数整除,所以b一定是1,2,3...a-1最小公倍数的倍数
for i in range(int(input())):
    a, n = map(int, input().split())
    m = my_lcm(a, n)
    if m:
        # 考虑容斥:1~n范围1,2,3...a-1最小公倍数的倍数的个数 - 1,2,3...a最小公倍数的倍数的个数即符合条件的b的个数
        p = n // m  # 现将所有可能的情况计算出来
        q = n // (m * a // gcd(m, a))  # 再计算出不合规的情况,(参考测试用例2)
        print(p - q)
    else:
        print(0)

你可能感兴趣的:(蓝桥杯,python)