第十四届(2023)蓝桥杯省赛python组部分真题(2)

1 异或和:3549

1.1 题目内容

在这里插入图片描述

1.2 题目分析

  • 树状数组 + DFS + 邻接表存储树
  • 一开始DFS整棵树,记录每个节点第一次访问的num和退出访问的num。
  • 得到了每个节点的[in,out],就可以计算出异或前缀和(in ~ out范围)。
  • 树状数组初始化update(该结点第一次访问的num,该结点的权值),刚开始初始化为0。
  • [l, r]的异或前缀和 = sums( r ) ^ sums(l - 1)。
  • 更新节点:update(该结点第一次访问的num,该结点的原权值 ^ 更改后的权值)
  • 异或:
    0 ^ a = a
    a ^ a = 0
    a ^ b ^ b = a

1.3 代码部分

import os
import sys

def dfs(now, fa):
  global num
  num += 1
  visit_num[now][0] = num
  for child in tree[now]:
    if child != fa:
      dfs(child, now)
  visit_num[now][1] = num

def lowbit(x):
  return x & -x 

def update(x, d):
  while x <= n:
    tree_list[x] ^= d
    x += lowbit(x)

def sums(x):
  ans = 0
  while x:
    ans ^= tree_list[x]
    x -= lowbit(x)
  return ans

n, m = map(int, input().split())
a = [0] + list(map(int, input().split()))
tree = [[] for _ in range(n + 1)]
for _ in range(n - 1):
  u, v = map(int, input().split())
  tree[u].append(v)
  tree[v].append(u)

visit_num = [[0, 0] for _ in range(n + 1)]
num = 0
dfs(1, 0)

tree_list = [0] * (n + 1)
for i in range(1, n + 1):
  update(visit_num[i][0], a[i])

for _ in range(m):
  s = list(map(int, input().split()))
  if s[0] == 1:
    update(visit_num[s[1]][0], a[s[1]] ^ s[2])
    a[s[1]] = s[2]
  else:
    res = sums(visit_num[s[1]][1]) ^ sums(visit_num[s[1]][0] - 1)
    print(res)

2 特殊日期:2408

2.1 题目内容

在这里插入图片描述

2.2 题目分析

  • 遍历每个日期,datetime.timedelta(1)增加每一天。

2.3 代码部分

import os
import sys
import datetime

'''
start = datetime.date(1900, 1, 1)
end = datetime.date(9999, 12, 31)
delta = datetime.timedelta(1)
num = 0
while start != end:
  a = start.year
  b = start.month
  c = start.day
  s1 = sum(map(int, list(str(a))))
  s2 = sum(map(int, list(str(b))))
  s3 = sum(map(int, list(str(c))))
  if s1 == s2 + s3:
    num += 1
  start += delta
print(num)
'''
print(70910)

3 三国游戏:3518

3.1 题目内容

在这里插入图片描述

3.2 题目分析

  • 贪心,每次取最大值。
  • 分为三种情况:X胜、Y胜、Z胜。
  • 根据三种情况分别将X - (Y + Z)、Y - (X + Z)、Z - (X + Y)降序排序
  • 从大数开始加,x,y,x中只要有一个 > 0就加一。

3.3 代码部分

import os
import sys

n = int(input())
A = list(map(int, input().split()))
B = list(map(int, input().split()))
C = list(map(int, input().split()))
a = sorted([A[i] - (B[i] + C[i]) for i in range(n)], reverse = True)
b = sorted([B[i] - (A[i] + C[i]) for i in range(n)], reverse = True)
c = sorted([C[i] - (A[i] + B[i]) for i in range(n)], reverse = True)
ans = 0
x, y, z = 0, 0, 0
for i in range(n):
  x += a[i]
  y += b[i]
  z += c[i]
  if x > 0 or y > 0 or z > 0:
    ans += 1
print(ans if ans != 0 else -1)

4 翻转:3520

4.1 题目内容

在这里插入图片描述

4.2 题目分析

  • 从第二个数开始判断,左边和右边相等且与当前数不同,则变换数字。
  • (首位如果不同,一定不存在方案。)
  • 判断变换后的字符串S是否和字符串T一致。

4.3 代码部分

import os
import sys

d = int(input())
for i in range(d):
  t = list(input())
  s = list(input())
  ans = 0
  for j in range(1, len(t) - 1):
    if s[j] == t[j]: continue
    elif s[j - 1] == s[j + 1] and s[j] != s[j + 1]:
      s[j] = s[j + 1]
      ans += 1
  if s == t: print(ans)
  else: print(-1)

5 平均:3532

5.1 题目内容

在这里插入图片描述

5.2 题目分析

  • 贪心
  • 排序,从最小的开始取,取times个。

5.3 代码部分

import os
import sys

n = int(input())
times = n // 10
nums = [[] for _ in range(10)]
for i in range(n):
  a, b = map(int, input().split())
  nums[a].append(b)
ans = 0
for i in range(10):
  n = sorted(nums[i])
  ans += sum(n[: -times])
print(ans)

6 分糖果:2928

6.1 题目内容

在这里插入图片描述

6.2 题目分析

  • 根据题意得,分给所有同学的字符串中,存在一个字典序列最大的字符串,要求出所有情况中,这个字典序列最大的字符串的最小值。
  • 首先将字符串排序。
  • 分为三种情况:
    ① 所有糖果相同。将所有糖果均分,字典序最大的字符串即为:(每个人分的个数 + 1(余数)) * [字符]。
    ② 所有糖果不相同,第一种糖果够分给所有同学。每名同学都分1个第一种糖果后,将剩下的所有糖果都分给一个人。
    ③ 所有糖果不相同,第一种糖果不够分给所有同学。第一轮中,最后一个分到糖果的同学,当前他所拥有的糖果字典序最大,将所有剩下的糖果都给他。

6.3 代码部分

import os
import sys

n, x = map(int, input().split())
s = list(input())
s.sort()
if len(set(s)) == 1:
  if n % x == 0:
    ma = (n // x) * s[0]
  else:
    ma = (n // x + 1) * s[0]
elif s.count(s[0]) >= x:
  ma = s[0] + "".join(s[x: ])
else:
  ma = s[x - 1]
print(ma)

总结

未完待续…

  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值