第十二届蓝桥杯国赛B组 做题记录(python)

填空题对了一个,大题对了三个还是四个,因为要做核酸提前一小时交卷了,蜂巢最长不下降子序列没来得及做,其他大题就是打表或者暴力。

好在最后还是拿了省一,稍微准备一手看能不能混个国三

还行,最后混了一手国二。

蓝桥杯

  • 结果填空
    • 整数范围(5分)
    • 纯质数(5分)
    • 完全日期(10分)
    • 最小权值(10分)
  • 程序设计
    • 大写(15分)
    • 123(15分) (45%)
    • 和与乘积(20分) (36%)
    • 巧克力(20分)(36%)
    • 翻转括号序列(25分)(5%)
    • 异或三角(25分)(9%)

结果填空

整数范围(5分)

问题描述

用 8 位二进制(一个字节)来表示一个非负整数,表示的最小值是 0,则一般能表示的最大值是多少?

答案提交

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

送分题,答案:255

纯质数(5分)

问题描述

   如果一个正整数只有 1 和它本身两个约数,则称为一个质数(又称素数)。
   前几个质数是:2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, · · · 。
   如果一个质数的所有十进制数位都是质数,我们称它为纯质数。例如:2, 3, 5, 7, 23, 37 都是纯质数,而 11, 13, 17, 19, 29, 31 不是纯质数。当然 1, 4, 35 也不是纯质数。
   请问,在 120210605 中,有多少个纯质数?

答案提交

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

也不算难,答案:1903

def su(x):
    if x != 2 and x%2 == 0:
        return False
    for i in range(3,int(x**0.5)+1,2):
        if x%i == 0:
            return False
    return True
def chun(x):
    lt = ['0','1','4','6','8','9'] #不要忽略0
    for i in lt:
        if i in str(x):
            return False
    return True
cnt = 0
for i in range(2,20210606):
    if chun(i) and su(i): #后判断是否是素数更节省时间
        cnt += 1
print(cnt)

完全日期(10分)

问题描述

如果一个日期中年月日的各位数字之和是完全平方数,则称为一个完全日期。

例如:202165 日的各位数字之和为 2 + 0 + 2 + 1 + 6 + 5 = 16,而 16 是一个完全平方数,它是 4 的平方。所以 202165 日是一个完全日期。

例如:2021623 日的各位数字之和为 2 + 0 + 2 + 1 + 6 + 2 + 3 = 16,是一个完全平方数。所以 2021623 日也是一个完全日期。

请问,从 200111 日到 20211231 日中,一共有多少个完全日期?

答案提交

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

这里用到datetime库(自带),简单介绍下用法

import datetime
## date 日期对象
#设置开始日期
start = datetime.date(2001,2,1)
#周几,范围0-6,0表示周一
print(start.weekday())
print(start.year) #年
print(start.month) #月
print(start.day) #日

思路就是先算出一系列符合完全日期的年月日组合,然后看合不合法,答案:977

import datetime

#合法性判断
def check(year,month,day):
    try:
        s = datetime.date(year,month,day)
        return True
    except:
        return False

sq = [1,4,9,16,25,36,49,64]
cnt = 0
#所有可能的年月日
y = [str(2001+i) for i in range(21)]
m = [str(1+i) for i in range(12)]
d = [str(1+i) for i in range(31)]

for i in y:
    suma = sum([int(_) for _ in i])
    for j in m:
        sumb = sum([int(_) for _ in j])
        for k in d:
            sumc = sum([int(_) for _ in k])
            if suma+sumb+sumc in sq and check(int(i),int(j),int(k)):
                cnt += 1
print(cnt)

最小权值(10分)

问题描述

对于一棵有根二叉树 T,小蓝定义这棵树中结点的权值 W(T) 如下:

空子树的权值为 0。

如果一个结点 v 有左子树 L, 右子树 R,分别有 C(L) 和 C(R) 个结点,则 W(v) = 1 + 2W(L) + 3W(R) + (C(L))^2 C(R)。

树的权值定义为树的根结点的权值。

小蓝想知道,对于一棵有 2021 个结点的二叉树,树的权值最小可能是多少?

答案提交

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

一眼DP,答案:2653631372

w = [float('inf')] * 2022
w[0] = 0
w[1] = 1

for i in range(2,2022):
    for j in range(i): #L=j  R=i-j-1
        w[i] = min(w[i],1 + 2*w[j] + 3*w[i-j-1] + j**2 * (i-j-1))
print(w[2021])

程序设计

蓝桥杯的练习系统中还没有第十二届决赛的题目,所以这里都是在C语言网上测试的,最终结果可能会有偏差。

大写(15分)

问题描述

给定一个只包含大写字母和小写字母的字符串,请将其中所有的小写字母 转换成大写字母后将字符串输出。

输入格式

输入一行包含一个字符串。

输出格式

输出转换成大写后的字符串。

样例输入 1

LanQiao

样例输出 1

LANQIAO

评测用例规模与约定

对于所有评测用例,字符串的长度不超过 100。

s = input()
print(s.upper())

123(15分) (45%)

问题描述

小蓝发现了一个有趣的数列,这个数列的前几项如下: 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, …

小蓝发现,这个数列前 1 项是整数 1,接下来 2 项是整数 1 至 2,接下来 3 项是整数 1 至 3,接下来 4 项是整数 1 至 4,依次类推。
小蓝想知道,这个数列中,连续一段的和是多少。

输入格式

输入的第一行包含一个整数 T,表示询问的个数。

接下来 T 行,每行包含一组询问,其中第 i 行包含两个整数 li 和 ri,表示询问数列中第 li 个数到第 ri 个数的和。

输出格式

输出 T 行,每行包含一个整数表示对应询问的答案。

样例输入

3
1 1
1 3
5 8

样例输出

1
4
8

评测用例规模与约定

对于 10% 的评测用例,1 ≤ T ≤ 30, 1 ≤ li ≤ ri ≤ 100。
对于 20% 的评测用例,1 ≤ T ≤ 100, 1 ≤ li ≤ ri ≤ 1000。
对于 40% 的评测用例,1 ≤ T ≤ 1000, 1 ≤ li ≤ ri ≤ 10^6。
对于 70% 的评测用例,1 ≤ T ≤ 10000, 1 ≤ li ≤ ri ≤ 10^9。
对于 80% 的评测用例,1 ≤ T ≤ 1000, 1 ≤ li ≤ ri ≤ 10^12。
对于 90% 的评测用例,1 ≤ T ≤ 10000, 1 ≤ li ≤ ri ≤ 10^12。
对于所有评测用例,1 ≤ T ≤ 100000, 1 ≤ li ≤ ri ≤ 10^12

笨方法,能拿45%的分

dic = {0:0}

#判断层数
def check(x):
    l = 0
    r = x+1
    while l<r:
        mid = l + r >>1
        if mid*(mid+1)//2 >= x:
            r = mid
        else:
            l = mid +1
    return l
#前x层共有多少个数
def cnt(x):
    if dic.get(x) == None:
        dic[x] = x*(x+1)//2
    return dic[x]

if __name__ == '__main__':
    t = int(input())
    for i in range(t):
        a,b = map(int,input().split())
        #位于的层数
        c = check(a)
        d = check(b)
        #位于当前层的第几位
        e = a-cnt(c-1)-1 
        f = b-cnt(d-1)
        if c == d: #同一层
            print((f*(f+1)-e*(e+1))//2)
        else:
            #左
            out = c*(c+1)//2 - e*(e+1)//2
            #中
            if d-c == 2:
                out += (d-1)*d // 2
            elif d-c > 2:
                for j in range(c+1,d):
                    out += j*(j+1)//2
            #右
            out += f*(f+1)//2
            print(out)

和与乘积(20分) (36%)

问题描述

给定一个数列 A = (a1, a2, · · · , an),问有多少个区间 [L, R] 满足区间内元素的乘积等于他们的和,即 aL ·
aL+1 · · · aR = aL + aL+1 + · · · + aR 。

输入格式

输入第一行包含一个整数 n,表示数列的长度。

第二行包含 n 个整数,依次表示数列中的数 a1, a2, · · · , an。

输出格式

输出仅一行,包含一个整数表示满足如上条件的区间的个数。

样例输入

4
1 3 2 2

样例输出

6

样例解释

符合条件的区间为 [1, 1], [1, 3], [2, 2], [3, 3], [3, 4], [4, 4]。

评测用例规模与约定

对于 20% 的评测用例,n, m ≤ 3000;
对于 50% 的评测用例,n, m ≤ 20000;
对于所有评测用例,1 ≤ n, m≤ 200000, 1 ≤ ai ≤ 200000。

超时了,只能拿36%的分

n = int(input())
#区间长度为1的情况
out = n

lt = list(map(int,input().split()))
for i in range(n-1):
    he = lt[i]
    cj = lt[i]
    for j in range(i+1,n):
        he += lt[j]
        cj *= lt[j]
        if he == cj:
            out += 1
print(out)

巧克力(20分)(36%)

问题描述

小蓝很喜欢吃巧克力,他每天都要吃一块巧克力。

一天小蓝到超市想买一些巧克力。超市的货架上有很多种巧克力,每种巧克力有自己的价格、数量和剩余的保质期天数,小蓝只吃没过保质期的巧克力,请问小蓝最少花多少钱能买到让自己吃x 天的巧克力。

输入格式

输入的第一行包含两个整数 x, n,分别表示需要吃巧克力的天数和巧克力的种类数。

接下来 n 行描述货架上的巧克力,其中第 i 行包含三个整数 ai , bi , ci,表示第 i 种巧克力的单价为 ai,保质期还剩 bi天(从现在开始的 bi 天可以吃),数量为 ci。

输出格式

输出一个整数表示小蓝的最小花费。如果不存在让小蓝吃 x 天的购买方案,输出 −1。

样例输入

10 3
1 6 5
2 7 3
3 10 10

样例输出

18

样例说明

一种最佳的方案是第 1 种买 5 块,第 2 种买 2 块,第 3 种买 3 块。前 5 天吃第 1 种,第 6、7 天吃第 2 种,第 8至 10 天吃第 3 种。

评测用例规模与约定

对于 30% 的评测用例,n, x ≤ 1000。
对于所有评测用例,1 ≤ n, x ≤ 100000,1 ≤ ai , bi , ci≤ 109。

按照保质期排序,可以发现,时间越往后,可选择的就越少,所以从最后一天往前判断。

拿到36%的分。

x,n = map(int,input().split())

ans = 0

lt = []
for i in range(n):
    lt.append(list(map(int,input().split())))

lt.sort(key = lambda x:x[1],reverse=True)

while x > 0:
    #存放在保质期内的巧克力
    ls = []
    for i in range(len(lt)):
        if lt[i][1] >= x:
            #记录下标
            ls.append(lt[i] + [i])
    #按照价格排序
    ls.sort(key = lambda x:x[0])
    #这一天没有巧克力可以吃
    if len(ls) == 0:
        ans = -1
        break
    else:
        ans += ls[0][0]
        if ls[0][2] == 1:
            lt.pop(ls[0][-1])
        else:
            #数量-1
            lt[ls[0][-1]][-1] -= 1
    x -= 1
print(ans)

翻转括号序列(25分)(5%)

问题描述

给定一个长度为 n 的括号序列,要求支持两种操作:

  1. 将 [Li , Ri ] 区间内(序列中的第 Li 个字符到第 Ri 个字符)的括号全部翻转(左括号变成右括号,右括号变成左括号)。

  2. 求出以 Li 为左端点时,最长的合法括号序列对应的 Ri (即找出最大的 Ri 使 [Li , Ri ] 是一个合法括号序列)。

输入格式

输入的第一行包含两个整数 n, m,分别表示括号序列长度和操作次数。

第二行包含给定的括号序列,括号序列中只包含左括号和右括号。

接下来 m 行,每行描述一个操作。如果该行为 “1 Li Ri”,表示第一种操作,区间为 [Li , Ri ] ;如果该行为 “2 Li”表示第二种操作,左端点为 Li。

输出格式

对于每个第二种操作,输出一行,表示对应的 Ri。如果不存在这样的 Ri,请输出 0。

样例输入

7 5
((())()
2 3
2 2
1 3 5
2 3
2 1

样例输出

4
7
0
0

评测用例规模与约定

对于 20% 的评测用例,n, m ≤ 5000;
对于 40% 的评测用例,n, m ≤ 30000;
对于 60% 的评测用例,n, m≤ 100000;
对于所有评测用例,1 ≤ n ≤ 10^6 , 1 ≤ m ≤ 2 × 10^5。

只骗了5%的分。。。

def check(ls):
    global L
    p = 0 #pop次数
    k = 0 #判断是否有合法括号序列
    stack = []
    stack.append(ls[0])
    for i in range(1,len(ls)):
        if ls[i] == '(':
            stack.append(ls[i])
        elif len(stack) == 0:
            break
        else:
            if stack[-1] == '(':
                stack.pop()
                if len(stack) == 0:
                    k = 1
                p += 1
    if k:
        return 2*p + L - 1
    else:
        return 0

n,m = map(int,input().split())
s = list(input())

for i in range(m):
    lt = list(map(int,input().split()))
    #操作2
    if len(lt) == 2:
        L = lt[-1]
        print(check(s[L-1:]))
    #操作1
    else:
        L = lt[1]
        R = lt[-1]
        mid = list("".join(s[L-1:R]).replace('(','0').replace(')','(').replace('0',')'))
        s = s[:L-1] + mid + s[R:]

异或三角(25分)(9%)

问题描述

给定 T 个数 n1, n2, · · · , nT,对每个 ni 请求出有多少组 a, b, c 满足:

  1. 1 ≤ a, b, c ≤ ni;

  2. a ⊕ b ⊕ c = 0,其中 ⊕ 表示二进制按位异或;

  3. 长度为 a, b, c 的三条边能组成一个三角形。

输入格式

输入的第一行包含一个整数 T。

接下来 T 行每行一个整数,分别表示 n1, n2, · · · , nT。

输出格式

输出 T 行,每行包含一个整数,表示对应的答案。

样例输入

2
6
114514

样例输出

6
11223848130

评测用例规模与约定

对于 10% 的评测用例,T = 1, 1 ≤ ni ≤ 200;
对于 20% 的评测用例,T = 1, 1 ≤ ni ≤ 2000;
对于 50% 的评测用例,T = 1, 1 ≤ ni ≤ 2^20;
对于 60% 的评测用例,1 ≤ T ≤ 100000, 1 ≤ ni ≤ 2^20;
对于所有评测用例,1 ≤ T ≤ 100000, 1 ≤ ni ≤ 2^30。

骗了9%的分

t = int(input())
for i in range(t):
    n = int(input())
    ans = 0
    for i in range(1,n+1): #最短边
        for j in range(i+1,n+1):
            for k in range(j+1,min(i+j,n+1)): #最长边
                if i^j == k:
                    ans += 6
    print(ans)

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