2020第十一届蓝桥杯国赛Python组

A美丽的2

2020第十一届蓝桥杯国赛Python组_第1张图片

答案:563

res = 0
for i in range(1, 2021):
    if '2' in str(i):
        res += 1
print(res)
# 563

B合数个数

2020第十一届蓝桥杯国赛Python组_第2张图片

模拟即可

答案:1713

def check(n):
    for i in range(2, n):
        if n % i == 0:
            return True
    return False


res = 0
for i in range(1, 2021):
    if check(i):
        res += 1
print(res)
# 1713

C阶乘约数

2020第十一届蓝桥杯国赛Python组_第3张图片

思路:需要一点数学知识

任意一个正整数n都可以表示成若干个素数的乘积: n = p 1 a 1 ∗ p 2 a 2 ∗ . . . ∗ p k a k n=p_{1} ^{a_{1}}*p_{2} ^{a_{2}}*...*p_{k} ^{a_{k}} n=p1a1p2a2...pkak

约 数 个 数 = ( a 1 + 1 ) ∗ ( a 2 + 1 ) ∗ . . . ∗ ( a k + 1 ) 约数个数=(a_{1}+1)*(a_{2}+1)*...*(a_{k}+1) =(a1+1)(a2+1)...(ak+1)

答案:39001250856960000

from math import *


def isPrime(n):
    for i in range(2, floor(sqrt(n))+1):
        if n % i == 0:
            return False
    return True


fac = {}
n = 100
for i in range(2, n+1):
    tmp = i
    num = 2
    while tmp > 1:
        while tmp % num == 0:
            fac[num] = fac.get(num, 0) + 1
            tmp //= num
        num += 1
        while not isPrime(num):
            num += 1

res = 1
for key, value in list(fac.items()):
    res *= value+1
print(res)
# 39001250856960000

D本质上升序列

2020第十一届蓝桥杯国赛Python组_第4张图片

思路:动态规划,和经典的最长不下降子序列类似,构造dp数组表示以第i个字符结尾的子序列的个数,对于字符串中每一个字符,遍历其前面的所有字符,若是当前字符比前面的大,满足递增要求,加上前面的数量;若是小于,不用理会;若是等于,由于当前的比前面的长,所以当前的包含了前面的,要减去前面的重复部分的数量。

答案:3616159

s = "tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl"
dp = [1]*len(s)  # dp[i]表示以第i个字符结尾的子序列的个数
for i in range(1, len(s)):
    for j in range(i):
        if s[i] > s[j]:
            dp[i] += dp[j]
        if s[i] == s[j]:
            dp[i] -= dp[j]  # 减去和前面重复的部分
print(sum(dp))
# 3616159

E玩具蛇

2020第十一届蓝桥杯国赛Python组_第5张图片

思路:深搜,没固定起点,所以每一个方格都作为起点搜一遍,注意下一次搜的时候把前一次的起点的状态还原。

答案:552

def dfs(x, y, current):
    global res
    if current > 16:
        res += 1
        return
    for i in range(4):
        tx, ty = x+dx[i], y+dy[i]
        if 0 <= tx < 4 and 0 <= ty < 4 and graph[tx][ty] == 0:
            graph[tx][ty] = current
            dfs(tx, ty, current+1)
            graph[tx][ty] = 0


res = 0
graph = [[0]*4 for _ in range(4)]
dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]
for i in range(4):
    for j in range(4):
        graph[i][j] = 1
        dfs(i, j, 2)
        graph[i][j] = 0
print(res)
# 552

F天干地支

【问题描述】
古代中国使用天干地支来记录当前的年份。
天干一共有十个,分别为:甲(jiǎ)、乙(yǐ)、丙(bǐng)、丁(dīng)、戊
(wù)、己(jǐ)、庚(gēng)、辛(xīn)、壬(rén)、癸(guǐ)。
地支一共有十二个,分别为:子(zǐ)、丑(chǒu)、寅(yín)、卯(mǎo)、辰(chén)、巳(sì)、午(wǔ)、未(wèi)、申(shēn)、酉(yǒu)、戌(xū)、亥(hài)。
将天干和地支连起来,就组成了一个天干地支的年份,例如:甲子。2020 年是庚子年。
每过一年,天干和地支都会移动到下一个。例如 2021 年是辛丑年。
每过 60 年,天干会循环 6 轮,地支会循环 5 轮,所以天干地支纪年每 60年轮回一次。例如 1900 年,1960 年,2020 年都是庚子年。
给定一个公元纪年的年份,请输出这一年的天干地支年份。
【输入格式】
输入一行包含一个正整数,表示公元年份。
【输出格式】
输出一个拼音,表示天干地支的年份,天干和地支都用小写拼音表示(不表示声调),之间不要加入任何多余的字符。
【样例输入】
2020
【样例输出】
gengzi
【评测用例规模与约定】
对于所有评测用例,输入的公元年份为不超过 9999 的正整数。

思路:

有个关于天干地支的计算方法:
(年份- 3)%10对天干:如1894-3=1891 ,1891除以10余数是1即为甲;
(年份- 3)%12对地支:如1894-3=1891 ,1891除以12余数是7即为午,即1894年是甲午年。

注意:如果下标从0开始就得减4

不过一般人不知道这个计算方法,那该怎么算呢?题目中说2020年是庚子年,将2020模一下60得到40,所以公元40年也是庚子年,把这个作为切入点按照规律走一遍就能得到一张模完60之后的映射表,代码如下:

year = int(input())
tiangan = ['jia', 'yi', 'bing', 'ding',
           'wu', 'ji', 'geng', 'xin', 'ren', 'gui']
dizhi = ['zi', 'chou', 'yin', 'mao', 'chen',
         'si', 'wu', 'wei', 'shen', 'you', 'xu', 'hai']
table = ['']*60
table[40] = tiangan[6]+dizhi[0]  # 公元40年是庚子年,依据这个建表,并且庚和子的下标分别是6和0

i, j = 7, 1
cnt = 41
while cnt != 40:
    table[cnt] = tiangan[i]+dizhi[j]
    i = (i+1) % 10
    j = (j+1) % 12
    cnt = (cnt+1) % 60
print(table[year % 60])
# 100%

G重复字符串

【问题描述】
如果一个字符串 S 恰好可以由某个字符串重复 K 次得到,我们就称 S 是 K 次重复字串。例如 “abcabcabc” 可以看作是 “abc” 重复 3 次得到,所以“abcabcabc” 是 3 次重复字符串。
同理 “aaaaaa” 既是 2 次重复字符串、又是 3 次重复字符串和 6 次重复字符串。
现在给定一个字符串 S,请你计算最少要修改其中几个字符,可以使 S 变为一个 K 次字符串?

【输入格式】
输入第一行包含一个整数 K。
第二行包含一个只含小写字母的字符串 S。

【输出格式】
输出一个整数代表答案。如果 S 无法修改成 K 次重复字符串,输出 1。

【样例输入】
2
aabbaa

【样例输出】
2

【评测用例规模与约定】
对于所有评测用例,1 ≤ K ≤ 100000, 1 ≤ |S | ≤ 100000。其中 |S | 表示 S 的
长度。

思路:将字符串分割成k段,假设每段m个字符,我们统计每段相同位置的每种字符出现的次数,每段都统计上后,每个位置(0 ~ m-1)都取出现次数最多的字符作为要变成的字符,将每一段的对应位置的字符都变成这个字符就行了,因为这个字符在该位置出现最多,其他字符变到该字符能保证次数最少,如果要是变成别的字符,那么出现次数最多的字符变动次数会很多,并非最优解。累加每个位置(0 ~ m-1)上变换次数就是答案。

k = int(input())
s = input()
if k > len(s):
    print(-1)
else:
    res = 0
    length = len(s)//k
    for i in range(length):
        dic = {}
        for j in range(k):
            word = s[j*length+i]
            dic[word] = dic.get(word, 0)+1
        d = list(dic.items())
        d.sort(key=lambda x: x[1], reverse=True)
        res += k-d[0][1]
    print(res)
# 100%

H答疑

【问题描述】
有 n 位同学同时找老师答疑。每位同学都预先估计了自己答疑的时间。
老师可以安排答疑的顺序,同学们要依次进入老师办公室答疑。
一位同学答疑的过程如下:

首先进入办公室,编号为 i 的同学需要 si 毫秒的时间。
然后同学问问题老师解答,编号为 i 的同学需要 ai 毫秒的时间。
答疑完成后,同学很高兴,会在课程群里面发一条消息,需要的时间可以忽略。
最后同学收拾东西离开办公室,需要 ei 毫秒的时间。一般需要 10 秒、
20 秒或 30 秒,即 ei 取值为 10000,20000 或 30000。
一位同学离开办公室后,紧接着下一位同学就可以进入办公室了。
答疑从 0 时刻开始。老师想合理的安排答疑的顺序,使得同学们在课程群
里面发消息的时刻之和最小
【输入格式】
输入第一行包含一个整数 n,表示同学的数量。
接下来 n 行,描述每位同学的时间。其中第 i 行包含三个整数 si, ai, ei,意
义如上所述。
【输出格式】
输出一个整数,表示同学们在课程群里面发消息的时刻之和最小是多少。
【样例输入】
3
10000 10000 10000
20000 50000 20000
30000 20000 30000
【样例输出】
280000
【样例说明】
按照 1, 3, 2 的顺序答疑,发消息的时间分别是 20000, 80000, 180000。
【评测用例规模与约定】
对于 30% 的评测用例,1 ≤ n ≤ 20。
对于 60% 的评测用例,1 ≤ n ≤ 200。
对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ si ≤ 60000,1 ≤ ai ≤ 1000000, ei ∈ {10000, 20000, 30000},即 ei 一定是 10000、20000、30000 之一。

思路:利用贪心的思想简单排序一下即可

若a在b前面,则a需要的时间为a的si+a的ei,b需要的时间为sum(a)+b的si+b的ei

若b在a前面,同理,两者比较一下即可。虽然做差的时候有几项是会约掉的,等效于sum(a)和sum(b)比较,但是写进去更便于理解。

代码如下:

from functools import cmp_to_key


def cmp(a, b):
    ta = a[0]+a[1]+sum(a)+b[0]+b[1]  # a在b前面,两人用的总时间
    tb = b[0]+b[1]+sum(b)+a[0]+a[1]  # b在a前面,两人用的总时间
    return ta-tb


n = int(input())
time = []
for _ in range(n):
    time.append(list(map(int, input().split())))
time.sort(key=cmp_to_key(cmp))
res = 0
clock = 0
for s, a, e in time:
    clock += s+a
    res += clock
    clock += e
print(res)
# 100%

I补给

【问题描述】
小蓝是一个直升飞机驾驶员,他负责给山区的 n 个村庄运送物资。每个月,他都要到每个村庄至少一次,可以多于一次,将村庄需要的物资运送过去。每个村庄都正好有一个直升机场,每两个村庄之间的路程都正好是村庄之间的直线距离。
由于直升机的油箱大小有限,小蓝单次飞行的距离不能超过 D。每个直升机场都有加油站,可以给直升机加满油。每个月,小蓝都是从总部出发,给各个村庄运送完物资后回到总部。如果方便,小蓝中途也可以经过总部来加油。
总部位于编号为 1 的村庄。请问,要完成一个月的任务,小蓝至少要飞行多长距离?

【输入格式】

输入的第一行包含两个整数n, D,分别表示村庄的数量和单次飞行的距离。

接下来n行描述村庄的位置,其中第i行两个整数 x i , y i x_{i},y_{i} xi,yi,表示编号为i的
村庄的坐标。村庄i和村庄j之间的距离为 ( x i − x j ) 2 + ( y i − y j ) 2 \sqrt{(x_{i}-x_{j})^{2}+(y_{i}-y_{j})^{2}} (xixj)2+(yiyj)2

【输出格式】
输出一行,包含一个实数,四舍五入保留正好 2 位小数,表示答案。

【样例输入】
4 10
1 1
5 5
1 5
5 1
【样例输出】
16.00
【样例说明】
四个村庄形成一个正方形的形状。

【样例输入】
4 6
1 1
4 5
8 5
11 1
【样例输出】
28.00
【样例说明】
补给顺序为 1 → 2 → 3 → 4 → 3 → 2 → 1。

【评测用例规模与约定】
对于所有评测用例,1 ≤ n ≤ 20, 1 ≤ xi, yi ≤ 104, 1 ≤ D ≤ 105。

思路:Floyd+状压dp

蓝桥杯练习系统里,python版本只能过80%(超时),c++相同思路能全过

from math import *


def getDistance(x, y):
    return sqrt(pow(location[x][0]-location[y][0], 2)+pow(location[x][1]-location[y][1], 2))


n, d = map(int, input().split())
location = [tuple(map(int, input().split())) for _ in range(n)]

w = [[float('inf')]*n for _ in range(n)]  # w[i][j]表示i号村庄和j号村庄之间的最短距离
# 建立邻接矩阵
for i in range(n):
    for j in range(n):
        dis = getDistance(i, j)
        if dis <= d:
            w[i][j] = dis

# Floyd算法
for k in range(n):
    for i in range(n):
        for j in range(n):
            w[i][j] = min(w[i][j], w[i][k]+w[k][j])

# dp[i][j]表示在状态i下,从0号村庄到j号村庄的最短录
dp = [[float('inf')]*n for _ in range(1 << n)]
dp[1][0] = 0
for i in range(1, 1 << n):  # 枚举状态
    for j in range(n):  # 枚举村庄
        if i >> j & 1 == 1:  # 如果j号村庄状态为1
            for k in range(n):
                if (i-(1 << j)) >> k & 1:  # 如果除了j号剩下的村庄中状态为1
                    dp[i][j] = min(dp[i][j], dp[i - (1 << j)][k]+w[k][j])

res = float('inf')
for i in range(n):  # 枚举最后从哪个村庄返回起点,也就是最后一个访问的村庄
    res = min(res, dp[(1 << n)-1][i]+w[i][0])
print('{:.2f}'.format(res))
# 80%

J蓝跳跳

【问题描述】
小蓝制作了一个机器人,取名为蓝跳跳,因为这个机器人走路的时候基本
靠跳跃。
蓝跳跳可以跳着走,也可以掉头。蓝跳跳每步跳的距离都必须是整数,每步可以跳不超过 k 的长度。由于蓝跳跳的平衡性设计得不太好,如果连续两次
都是跳跃,而且两次跳跃的距离都至少是 p,则蓝跳跳会摔倒,这是小蓝不愿意看到的。
小蓝接到一个特别的任务,要在一个长为 L 舞台上展示蓝跳跳。小蓝要控制蓝跳跳从舞台的左边走到右边,然后掉头,然后从右边走到左边,然后掉头,然后再从左边走到右边,然后掉头,再从右边走到左边,然后掉头,如此往复。为了让观者不至于太无趣,小蓝决定让蓝跳跳每次用不同的方式来走。小蓝将蓝跳跳每一步跳的距离记录下来,按顺序排成一列,显然这一列数每个都不超过 k 且和是 L。这样走一趟就会出来一列数。如果两列数的长度不同,或者两列数中存在一个位置数值不同,就认为是不同的方案。
请问蓝跳跳在不摔倒的前提下,有多少种不同的方案从舞台一边走到另一边。
【输入格式】
输入一行包含三个整数 k, p, L。
【输出格式】
输出一个整数,表示答案。答案可能很大,请输出答案除以 20201114 的余数。
【样例输入】
3 2 5
【样例输出】
9
【样例说明】
蓝跳跳有以下 9 种跳法:

1+1+1+1+1
1+1+1+2
1+1+2+1
1+2+1+1
2+1+1+1
2+1+2
1+1+3
1+3+1
3+1+1
【样例输入】
5 3 10
【样例输出】
397
【评测用例规模与约定】
对于 30% 的评测用例,1 ≤ p ≤ k ≤ 50,1 ≤ L ≤ 1000。
对于 60% 的评测用例,1 ≤ p ≤ k ≤ 50,1 ≤ L ≤ 109。
对于 80% 的评测用例,1 ≤ p ≤ k ≤ 200,1 ≤ L ≤ 1018。
对于所有评测用例,1 ≤ p ≤ k ≤ 1000,1 ≤ L ≤ 1018。

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