蓝桥杯 Python 组省赛夺奖班-2.3Python杂题

一、修剪灌木

题目

请添加图片描述

思路

树木编号为1、2、3…N,首先确定一个事情,就是树木的生长高度不会无限高,在2N个时间内会被修剪为0
那么对于第 i 棵树,从被修剪过到下此次修剪的最长时间为max(2*(i-1),2*(N-i)),这里的2是因为有一个转变修剪方向的过程。

代码

n = int(input())
for i in range (1,n+1):
    print(2*max((i-1),(n-i)))

二、付账问题

题目

请添加图片描述

思路

为了让最终出钱数目的标准差小,那么每个人出的钱不能相差太大。虽然有人带的钱少,有人带的钱多,但是不能让带钱多的人没有底线地当“冤大头”。那么先对所有人的带钱数进行一个排序,然后可以如果一个人的钱少于平均出钱数,那么这个人必须全出,然后将账单金额减去这个人的钱,剩下的钱由剩下的人出,这么看其实就是一个大问题转化为小问题的过程,有点类似于递归。这个过程中要不断更新剩下人的平均出钱数。编码有一点复杂。

代码

n,bill = map(int,input().split())
money = list(map(int,input().split()))

mean = bill/n
money.sort()

newmean = mean
newbill = bill
ans = 0
for i in range(n):
    if money[i] < newmean:
        ## 全出
        ans += ((money[i]-mean)**2/n)
        newbill -= money[i]
        newmean = newbill/(n-i-1)
    else:
        ## 够了
        ans += ((newmean-mean)**2/n)*(n-i)
        break
print("%.4f"%pow(ans,0.5))

三、最少砝码

题目

请添加图片描述

思路

如果下过围棋可能听过“置之死地而后生”,这个思路就和“置之死地而后生”有点类似。
如果我已经知道了R以内最少砝码的方案,如果我加入一个砝码(这里为什么是一个砝码,是因为如果要求砝码最少那么每个砝码的贡献应该最大化)质量为W,那么能称出的质量为:1、2…R 和 W-R、W-R+1、…W、…W+R,如果R和W-R相邻即W-R=R+1那么这种情况就是贡献最大化的情况。求得W=2R+1,那么有以下结论
已知R的最少砝码方案,增加一个砝码能够得到3R+1的最少砝码方案

然后配凑出一个等比数列化简完就是下面的代码

代码

import math
n = int(input())
print(math.ceil(math.log(2*n+1,3)))

四、矩阵拼接

题目

请添加图片描述
请添加图片描述

思路

四边形:

  • 三个三角形存在一个同样长度的边
  • 一个三角形的一边是另外两个三角形某一边的和,且另外两条边长度相同
    请添加图片描述
    请添加图片描述

六边形:

  • 一个三角形的一边是另外两个三角形某一边的和
    请添加图片描述

八边形:

  • 不满足上面的所有情况,直接放在一条线上即可
    请添加图片描述

代码

n = int(input())
def edge(a,b,c):
    ans = 8
    for i in range(2):
        if a[i] in b and a[i] in c:
            return 4
    for i in range(2):
        for j in range(2):
            for k in range(2):
                if a[i]+b[j] == c[k]:
                    ans = min(ans,6)
                    if a[1-i] == b[1-j]:
                        return 4
                if a[i] == b[j]:
                    ans = min(ans,6)
                    if a[1-i]+b[1-j] == c[k]:
                        return 4
    return ans
for i in range(n):
    temp = list(map(int,input().split()))
    print(min(edge(temp[:2],temp[2:4],temp[4:]),edge(temp[2:4],temp[4:],temp[:2]),edge(temp[4:],temp[:2],temp[2:4])))

五、蜂巢

题目

请添加图片描述

思路

这个有点难搞,曲曲折折,准备单独写一篇文章讲

代码

t = pow(3,0.5)
n = list(map(int,input().split()))
def trans(a,b,c):
    temp = [[-1,0],[-1/2,t/2],[1/2,t/2],[1,0],[1/2,-t/2],[-1/2,-t/2]]
    a_x = temp[a][0]*b+temp[(a+2)%6][0]*c
    a_y = temp[a][1]*b+temp[(a+2)%6][1]*c
    return [a_x,a_y]
a = trans(n[0],n[1],n[2])
b = trans(n[3],n[4],n[5])

d_x = abs(a[0]-b[0])
d_y = abs(a[1]-b[1])
if t*d_x < d_y:
    print(round(d_y/(t/2)))
else:
    print(round(d_y/(t/2)+(d_x-(d_y/t))))

或者

t = 2
n = list(map(int,input().split()))
def trans(a,b,c):
    temp = [[-1,0],[-1/2,t/2],[1/2,t/2],[1,0],[1/2,-t/2],[-1/2,-t/2]]
    a_x = temp[a][0]*b+temp[(a+2)%6][0]*c
    a_y = temp[a][1]*b+temp[(a+2)%6][1]*c
    return [a_x,a_y]
a = trans(n[0],n[1],n[2])
b = trans(n[3],n[4],n[5])

d_x = abs(a[0]-b[0])
d_y = abs(a[1]-b[1])
if t*d_x < d_y:
    print(int(d_y/(t/2)))
else:
    print(int(d_y/(t/2)+(d_x-(d_y/t))))

六、成绩分析

题目

请添加图片描述

思路

模拟 ,可以不用列表

代码

n = int(input())
score = []
for i in range(n):
    score.append(int(input()))
so_sum = sum(score)
so_max = max(score)
so_min = min(score)
so_mean = so_sum/n
print("%d\n%d\n%.2f"%(so_max,so_min,so_mean))

七、图像模糊

题目

请添加图片描述

思路

如果学过数字图像处理一定会想到在外围加一圈0,然后再算,这是一种通法,当然也可以只根据这个题目写出不同的情况。
外圈加零如图所示:
请添加图片描述

代码

import math
n,m = map(int,input().split())
graph = [[0]*(m+2) for _ in range(n+2)]
trgraph = [[0]*m for _ in range(n)]
for i in range(1,n+1):
    graph[i] = [0]
    graph[i].extend(list(map(int,input().split())))
    graph[i].append(0)
for i in range(1,n+1):
    for j in range(1,m+1):
        p_sum = sum([graph[i-1][j-1],graph[i-1][j],graph[i-1][j+1],graph[i][j-1],graph[i][j],graph[i][j+1],graph[i+1][j-1],graph[i+1][j],graph[i+1][j+1]])
        if [i,j] == [1,1] or [i,j] == [n,1] or [i,j] == [1,m] or [i,j] == [n,m]:
            print(math.floor(p_sum/4),end = " ")
            trgraph[i-1][j-1] = math.floor(p_sum/4)
        elif i == 1 or j == 1 or i == n or j == m:
            print(math.floor(p_sum/6),end = " ")
            trgraph[i-1][j-1] = math.floor(p_sum/6)
        else:
            print(math.floor(p_sum/9),end = " ")
            trgraph[i-1][j-1] = math.floor(p_sum/9)
    print("\n")

八、子串分值

题目

请添加图片描述

思路

n的量级在10^5,如果使用暴力枚举出所有的关系大部分案例会超时,那么需要将复杂度降低,可以从每个字符对于结果的贡献入手,对于一个字符如果要产生得分需要子串中只有一个该字符,那么只需要看距离这个字符最近的同种字符的位置即可,可得下面的结论
请添加图片描述
开始可以对每个字符探测左右相同字符的位置,然后根据上面的结论计算每个字符的得分

代码

暴力法

暴力法只能过几个例子

import itertools
n = input()
ans = 0
def check(a):
    a_set = set([i for i in a])
    a_res = 0
    for i in a_set:
        if a.count(i) == 1:
            a_res += 1
    return a_res
cnt = 0
for length in range(1,len(n)+1):
    for j in range(0,len(n)-length+1):
        ans += check(n[j:j+length])
print(ans)
“优雅”法

“优雅”永不过时

n = input()
left = [None for _ in range(len(n))]
right = [None for _ in range(len(n))]
def scan():
    for i in range(0,len(n)):
        for j in range(i-1,-1,-1):
            if n[j] == n[i]:
                left[i] = j
                break
        for k in range(i+1,len(n)):
            if n[k] == n[i]:
                right[i] = k
                break
ans = 0
scan()
for i in range(len(n)):
    if left[i] == None and right[i] == None:
       ans += (i+1)*(len(n)-i)
    elif left[i] == None:
        ans += (i+1)*(right[i]-i)
    elif right[i] == None:
        ans += (i-left[i])*(len(n)-i)
    else:
        ans += (i-left[i])*(right[i]-i)
print(ans)

附加题

一、子串分值和

题目

请添加图片描述

思路

参考子串分值的思路,只是对于分值的分配不同这里采用的是分值全部给最右边的字符,当然也可以给左边(给左边就要探测左边界)。一开始想的是给分数分值,但是这样不是通法,包含的字符数不太可能统一,分数分值最后统计也很麻烦。

代码

n = input()
right = [None for _ in range(len(n))]
def scan():
    for i in range(len(n)):
        for j in range(i+1,len(n)):
            if n[j] == n[i]:
                right[i] = j
                break
scan()
ans = 0
for i in range(len(n)):
    if right[i] == None:
        ans += (i+1)*(len(n)-i)
    else:
        ans += (i+1)*(right[i]-i)
print(ans)

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值