蓝桥杯 真题散装

文章探讨了如何通过贪心算法对消息发送时间进行排序,涉及特殊时间约束(如月份和闰年),以及使用差分、动态规划和线性筛等方法解决日期计算、硬币兑换和纯素数问题。
摘要由CSDN通过智能技术生成

 1.答疑排队

"""
列出时间,第一条消息发出为:t1=s1+a1,第二条消息发出为t2=t1+e1+s2+a2...
容易看出,si+ai 可以看成一份,si+ai+ei 也可以看成一份,方便计算
将si+ai 视为Ai si+ai+ei视为Bi,t1 = A1, t2 = B1+A2, t3 = B1+B2+A3...
贪心思想,Ai越小,发消息的时刻越靠前。所以根据A的值排序。
"""

n = int(input())
li = []
for i in range(n):
    x,y,z = map(int,input().split())
    a = x+y
    b = x+y+z
    li.append([a,b])
li = sorted(li,key=lambda x:x[1],reverse=False)
t = 0
for i in range(n):
    for j in range(i):
        t += li[j][1]
    t += li[i][0]
print(t)

""" 参考上面代码思想后自己写的:"""
n = int(input())
lst = []
for i in range(n):
    x,y,z = map(int,input().split())
    a = x+y
    b = x+y+z
    lst.append([a,b])
    
lst = sorted(lst,key=lambda x:x[1],reverse=False)
# print(lst)
ta = 0
tb = 0
tb_lst = []
for i in range(n):
    ta += lst[i][0]
    # print("ta=",ta)
    if i < n-1:
        tb += lst[i][1]
        tb_lst.append(tb)
        # print("tb=",tb)
print(ta+sum(tb_lst))

2.特殊时间

"""
冷静思考,理性分析。约束最大的是月份,其次是时间,年份无限制。
"""
# 合法的日期(月日)取值仅有以下16种:
# 0111,0222,1011,1211,1222,1101,1121,1110,1112,1113,1114,1115,1116,1117,1118,1119
# 创建一个列表分别储存每个日期(月日)对应的合法时间个数:
time = [4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2]
# 年份无限制,每个数乘4即可
year = [4 * i for i in time]
print(sum(year))

3.天干地支

"""
注意第一个甲子年是从公园4年开始的,year需要减去初始值
"""
year = int(input()) - 4
year = year % 60
tiangan = ['jia','yi','bing','ding','wu','ji','geng','xin','ren','gui']
dizhi = ['zi','chou','yin','mao','chen','si','wu','wei','shen','you','xu','hai']
# 无需循环,直接求余
a = year%10
b = year%12
print(tiangan[a]+dizhi[b])

4.特殊日期

"""
法一
处理月份和闰年的方法值得学习:
使用每个月天数和30天的差值 简化
使用哈希表存储 月份和 每个月份数位和+日数位和的区间
闰年特殊处理,日期固定为2.29,反过来限制年份即可
"""

# 请在此输入您的代码
def isLeap(x):  # 判断是否为闰年
    if (x % 4 == 0 and x % 100 != 0) or x % 400 == 0:
        return True
    return False

def numAdd(x):  # 计算年份个数位的数字和
    sums = 0
    while x:
        sums += x % 10
        x //= 10
    return sums


start, end = 1900, 9999
ans = 0
day = [1, -2, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1]  # 每个月天数和30天的差值
data = []
hstable = dict()  # key:月份1~12,value:每个月份月份数位和+日的数位和的区间,如1月份为(2, 32)
for j in range(1,32):  # 计算日数位和
    data.append(numAdd(j))
for i in range(1, 13):  # 初始化哈希表
    t = numAdd(i)  # 月数位和
    for j in range(day[i - 1] + 30):  # 遍历一个月的每一天将月数位和加上日数位和
        addt = t + data[j]
        if addt not in hstable:
            hstable[addt] = 1  
        else:
            hstable[addt] += 1  # 哈希表中对应的天数加一

for i in range(start, end + 1):  # 遍历每一年
    yearsum = numAdd(i)  # 计算年的数位和
    if yearsum in hstable:  # 若年的数位和在哈希表中存在则答案加上对应的天数
        ans += hstable[yearsum]
    if isLeap(i) and yearsum == 13:  # 闰年2月份多一天,位数和为13
        ans += 1

print(ans)


"""
法二 自己写的简陋东西,思路更直接
"""
def shuzihe(x):    # 数字和
    tmp1 = str(x)
    tmp_sum = 0
    for t in tmp1:
        tmp_sum += int(t)
    return tmp_sum
def leapyear(y):    # 判断闰年
    if (y % 4 == 0 and y%100!=0) or y%400 == 0:
        return True
    return False

cnt = 0
for i in range(1900,10000):    # 年份
    a = shuzihe(i)
    for j in range(1,13):    # 月份
        b = shuzihe(j)
        for k in range(1,32):    # 日期
            c = shuzihe(k)
            if a == b+c:    # 判断条件
                cnt += 1
                if j == 2 and (k == 30 or k == 31):    # 去除2月30.31
                    cnt -= 1
                if (not leapyear(i)) and j == 2 and k == 29:    # 去除2.29在非闰年
                    cnt -=1
                if j in [4,6,9,11] and k == 31:    # 去除小月份
                    cnt -= 1
print(cnt)  #70910

5.玩具蛇

"""
dfs 注意flag的回溯处理
"""

flag = [[0] * 4 for i in range(4)]  # 开 4 * 4 的矩阵,用于做标记 
#不可以[[0]*4]*4 这样每一行其实是引用了相同的列表,而不是独立的列表。这意味着当你修改一个行的值时,其他行的对应位置的值也会被修改。
ans = 0  # 记录最终结果
direction = [[1, 0], [0, 1], [-1, 0], [0, -1]]  # 4 个方向


def dfs(x, y, count):  # x,y 是坐标,count 是计数器
    global ans  # 对 ans 进行全局变量修改
    if count == 16:  # 如果 16 节全放下了
        ans += 1  # 结果 +1,退出本起点的搜索
        return
    for d in direction:  # 对 4 个方向进行搜索
        dx = x + d[0]
        dy = y + d[1]
        if 0 <= dx < 4 and 0 <= dy < 4 and flag[dx][dy] != 1:  
        # 防止越界,以及只走 flag == 0 的点位
            flag[dx][dy] = 1  # 把满足条件的该点设为 1
            dfs(dx, dy, count + 1)  # 基于该点继续搜索
            flag[dx][dy] = 0  # 搜索完记得消除痕迹


for i in range(4):  # i,j 等于 x,y
    for j in range(4):
        flag[i][j] = 1  # 标记起点已经过
        dfs(i, j, 1)  # 从起点开始搜索
        flag[i][j] = 0  # 最后记得清除起点的痕迹
print(ans)

6.火柴棒数字

优先考虑位数!!

"""
优先考虑位数,从需要火柴数小的开始排,同等数量选数字大的。
"""
nums = [(0,6),(1,2),(2,5),(3,5),(4,4),(5,5),(6,6),(7,3),(8,7),(9,6)]
# print(sorted(nums,key=lambda x:x[1]))
# [(1, 2), (7, 3), (4, 4), (2, 5), (3, 5), (5, 5), (0, 6), (6, 6), (9, 6), (8, 7)]
print(int('9'*10+'7'*10+'5'*10+'4'*10+'3'*10+'2'*10+'1'*10))
# 9999999999777777777755555555554444444444333333333322222222221111111111

7.硬币兑换

通过遍历所有可能的新版硬币面值组合,计算它们兑换成旧版硬币的总价值,并将结果存储在一个长度为4047的列表中。最后找出列表中最大的值,即682425 

由于每个新版硬币的面值范围是1到2023,而且每种面值的硬币数量分别为1到2023,所以理论上每个面值的硬币数量可能的取值范围也是1到2023。

"""
内层循环的目的是计算两个新版硬币的面值之和,并将该值加到结果列表中相应的位置上。
所以内层循环从i+1开始,避免重复计算引起结果出错
"""
result = [0 for r in range(4047)]  # 建立一个长为4047的全0列表
for i in range(1, 2024):  # 往前加
    for j in range(i+1, 2024):
        result[i + j] += i
print(max(result))  #682425

8.棋盘

 运用差分可以简化计算。

使用差分的思想来标记某个区域的起始位置和结束位置之后的下一个位置。通过将起始位置加1,结束位置下一个位置减1,可以在后续的处理中方便地计算出每个位置的最终值。

然后,在第9到11行的双重循环中,使用差分的思想对整个矩阵进行更新。根据提供的公式,通过当前位置、左边、上边和左上角位置的差分值,可以计算出当前位置的新值。

n, m = map(int, input().split())
mat = [[0 for _ in range(n + 2)] for _ in range(n + 2)]
for _ in range(m):
    x1, y1, x2, y2 = map(int, input().split())
    mat[x1][y1] += 1
    mat[x1][y2 + 1] -= 1
    mat[x2 + 1][y1] -= 1
    mat[x2 + 1][y2 + 1] += 1
for i in range(1, n + 1):
    for j in range(1, n + 1):
        mat[i][j] = (mat[i][j] + mat[i][j - 1] + mat[i - 1][j] - mat[i - 1][j - 1]) % 2
        print(mat[i][j], end='')
    print()

差分是一种常见的算法技巧,用于在数列中快速计算前缀和或反推数列的原始值。在差分中,我们通过对相邻元素之间的差值进行操作来实现对目标数列的处理。

具体来说,如果有一个数列 (a),我们可以构造一个新的数列 (d),其中 (d_i = a_i - a_{i-1})。这个新数列 (d) 就被称为原数列 (a) 的差分数列。通过对差分数列的操作,我们可以快速计算出原数列的前缀和或根据前缀和反推回原数列的值。

举例来说,假设原数列为 ([1, 3, 5, 7, 9]),那么它的差分数列就是 ([1, 2, 2, 2, 2])。通过对差分数列求前缀和,我们可以还原回原数列:

  • 差分数列 ([1, 2, 2, 2, 2])
  • 前缀和 ([1, 3, 5, 7, 9])

下面是一个简单的示例 Python 代码,演示了如何使用差分和前缀和来实现数列的变换:

"""差分"""
# 原数列
a = [1, 3, 5, 7, 9]

# 计算差分数列
d = [a[i] - a[i-1] for i in range(1, len(a))]
d.insert(0, a[0])  # 差分数列的第一个元素与原数列相同

# 计算前缀和还原回原数列
prefix_sum = [d[0]]
for i in range(1, len(d)):
    prefix_sum.append(prefix_sum[i-1] + d[i])

print("原数列:", a)
print("差分数列:", d)
print("前缀和还原:", prefix_sum)

9.本质上升序列

"""
动态规划 不懂不懂不懂
"""

x = "tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl"
dp = [1] * 200    # 设置列表存储每个位置为开头的子序列
for i in range(200):
    for j in range(i):
        if x[i] > x[j]:    # 
            dp[i] += dp[j]
        elif x[j] == x[i]:
            dp[i] -= dp[j]
print(dp)
print(sum(dp))

10.纸牌三角形

 itertools 模块的基本使用见尺取和枚举 python-CSDN博客

"""
全排列+三角形表达找到三遍和相等的三角形,因为旋转(3种)*对称(2种)多余六种,结果需要//6
"""
from itertools import permutations  # 导入全排列函数
cnt = 0
# 生成数字1到9的所有排列方式
perms = list(permutations(range(1, 10)))
#print(perms)
for i in perms: # perms 是所有1-10的全排列
    # 计算三条边的和,学习模拟排列三角形的方法!!! 
    a = i[0] + i[1] + i[2] + i[3]
    b = i[0] + i[4] + i[5] + i[6]
    c = i[3] + i[6] + i[7] + i[8]

    # 如果三条边的和相等,则符合条件,计数加1
    if a == b == c:
        cnt += 1

print(cnt // 6)  # 144种排法

10.纯素数

"""
法一 埃氏筛筛质数列表,再减去其中单位数字含非质数的个数。相比起减去质数列表内容快一些。 
"""
res = []
counts = 0
lst = [True for _ in range(20210606)]    # 初始化为全部正确的列表
for i in range(2,20210606):    # 遍历
    if lst[i]:
        res.append(i)    # 添加质数
        counts += 1
        for j in range(i+i, 20210606, i):    # 往后把i的倍数全部设为False
            lst[j] = False
for ans in res:    # 用字符串in找含有非质数的质数
    if "0" in str(ans) or "1" in str(ans) or "4" in str(ans) or "6" in str(ans) or "8" in str(ans) or "9" in str(ans):
        counts -= 1
print(counts)


"""
法二 线性筛,先列出20210605内的所有质数,再减去单位数字中非质数的个数
"""
def zhishu(n):
    is_prime = [True]*(n+1)
    is_prime[0] = is_prime[1] = False
    p = 2
    while p**2<=n:    # 判断是否为质数
        if is_prime[p]:
            for i in range(p*p, n+1, p):
                is_prime[i] = False
        p += 1
    primes = []
    for i in range(2, n+1):
        if is_prime[i]:
            primes.append(i)
    return primes
primes = zhishu(20210605)
count = len(primes)
for ans in primes:
    if "0" in str(ans) or "1" in str(ans) or "4" in str(ans) or "6" in str(ans) or "8" in str(ans) or "9" in str(ans):
        count -= 1
print(count)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值