第十一届蓝桥杯大赛软件赛国赛(Python大学组)

2020年蓝桥杯  省赛真题
Python大学组

        试题A:美丽的2
        试题B:合数个数
        试题C:阶乘约数
        试题D:本质上升序列
        试题E:玩具蛇
        试题F:天干地支
        试题G:重复字符串
        试题H:答疑
        试题I:补给
        试题J:蓝跳跳


试题A:美丽的2     (5分)

【题目描述】

        小蓝特别喜欢 2,今年是公元 2020 年,他特别高兴。 他很好奇,在公元 1 年到公元 2020 年(包含)中,有多少个年份的数位中包含数字 2?

【答案提交】

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

【解析与方法】

        直接遍历1~2020,将数字转为字符串,使用count函数判断。

【Python程序与代码】

res = 0
for i in range(1,2021):
  tep = str(i)
  if tep.count('2'):res+=1
print(res)

最终结果: 563


试题B:合数个数     (5分)

【题目描述】

        一个数如果除了 1 和自己还有其他约数,则称为一个合数。例如:1,2,3 不是合数,4,6 是合数。
        请问从 1 到 2020 一共有多少个合数。

【答案提交】

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

【解析与方法】

        直接遍历1-2020,判断其是不是素数就可以,不是素数就是合数。

【Python程序代码】

def pd(x):
    j = 2
    while j*j<=x:
        if x%j==0:
            return True
        j += 1
    return False
res = 0
for i in range(2,2021):
    if pd(i):
        res += 1
print(res)

最终结果:1713


 试题C:阶乘约数     (10分)

【题目描述】

        定义阶乘 n!=1×2×3×⋅⋅⋅×n。请问 100!(100 的阶乘)有多少个正约数。

【答案提交】

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

【解析与方法】

         任何一个大于等于2的整数都可以分解成若干个质数的pi次幂的积的形式,所以总的正约数个数为,∏(pi+1)

【Python程序代码】

from collections import defaultdict
dic,res = defaultdict(int),1
def work(x):
    j = 2
    while j*j<=x:
        if x%j==0:
            while x%j==0:
                dic[j] += 1
                x //= j
        else:
            j += 1
    if x>1:
        dic[x] += 1
for i in range(2,101):
    work(i)
for i in range(2,101):
   res *= (dic[i]+1)
print(res)

最终结果:39001250856960000


试题 D:蛇形填数     (10分)

【题目描述】

        小蓝特别喜欢单调递增的事物。在一个字符串中,如果取出若干个字符,将这些字符按照在字符串中的顺序排列后是单调递增的,则成为这个字符串中的一个单调递增子序列。
        例如,在字符串 lanqiao 中,如果取出字符 n 和 q,则 nq 组成一个单调递增子序列。类似的单调递增子序列还有 lnq、i、ano 等等。 小蓝发现,有些子序列虽然位置不同,但是字符序列是一样的,例如取第二个字符和最后一个字符可以取到 ao,取最后两个字符也可以取到 ao。小蓝认为他们并没有本质不同。
        对于一个字符串,小蓝想知道,本质不同的递增子序列有多少个? 例如,对于字符串 lanqiao,本质不同的递增子序列有 21 个。它们分别是 l、a、n、q、i、o、ln、an、lq、aq、nq、ai、lo、ao、no、io、lnq、anq、lno、ano、aio
        请问对于以下字符串(共 200个小写英文字母,分四行显示):本质不同的递增子序列有多少个?

tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhf
iadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqij
gihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmad
vrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl

【答案提交】

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

【解析与方法】

        字符串太长搜索貌似不太行,直接DP,设dp[i]为以i结尾的字符串的不同递增字串个数,则当x[i]>x[j]时,dp[i] += dp[j],因为要不同则,当x[i]==x[j]时dp[i]-=dp[j]。

【Python程序代码】

x = "tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl"
f = [1]*200
for i in range(200):
    for j in range(i):
        if x[i]>x[j]:
            f[i] += f[j]
        elif x[i]==x[j]:
            f[i] -= f[j]
print(sum(f))

最终结果:3616159


 试题E:玩具蛇    (15分)

【题目描述】

        小蓝有一条玩具蛇,一共有 16 节,上面标着数字 1至 16。每一节都是一个正方形的形状。相邻的两节可以成直线或者成 90 度角。小蓝还有一个 4×4 的方格盒子,用于存放玩具蛇,盒子的方格上依次标着字母 A 到 P 共 16个字母。
        小蓝可以折叠自己的玩具蛇放到盒子里面。他发现,有很多种方案可以将玩具蛇放进去。
        下图给出了两种方案:

        请帮小蓝计算一下,总共有多少种不同的方案。如果两个方案中,存在玩具蛇的某一节放在了盒子的不同格子里,则认为是不同的方案。

【答案提交】

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

【解析与方法】

        属于比较明显的暴力搜索了,个人做法是枚举每个起点开始搜索,这样一定会有重复,所以用了一个set去重。比较简单。

【Python程序代码】

res = 0
mp = [[0]*4 for _ in range(4)]
dic = [(1,0),(0,1),(0,-1),(-1,0)]
s = set()
def dfs(x,y,u):
    global res
    if u==17:
        tep=""
        for i in range(4):
            for j in range(4):
                tep += str(mp[i][j])
        s.add(tep)
        return
    for i in range(4):
        tx,ty = x+dic[i][0],y+dic[i][1]
        if tx<0 or tx>=4 or ty<0 or ty>=4:continue
        if mp[tx][ty]:continue
        mp[tx][ty]=u
        dfs(tx,ty,u+1)
        mp[tx][ty]=0
    return
for i in range(4):
    for j in range(4):
        dfs(i,j,1)
print(len(s))
    

 最终结果:552


 试题F:天干地支     (15分)

【题目描述】

        古代中国使用天干地支来记录当前的年份。天干一共有十个,分别为:甲(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 轮,地支会循环 55轮,所以天干地支纪年每 60 年轮回一次。例如1900年,1960 年,2020 年都是庚子年。给定一个公元纪年的年份,请输出这一年的天干地支年份。

【输入描述】

        输入一行包含一个正整数,表示公元年份。
        其中有 ,输入的公元年份为不超过 9999 的正整数。

【输出描述】

        输入一行包含一个正整数,表示公元年份。

【输入样例】

2020

【输出样例】

gengzi

【测试用例与规模】

        对于所以的评测用例,1<n<10000。

【解析与方法】

        额根据周期性和已经给出的年份找偏移量,直接无脑一个一个试就行。然后再用2021是辛丑做测试,就出来了。

【Python程序代码】

tg = ["jia","yi","bing","ding","wu","ji","geng","xin","ren","gui"]
dz = ["zi","chou","yin","mao","chen","si","wu","wei","shen","you","xu","hai"]
year = int(input())
print((tg[(year+6)%10]+dz[(year+8)%12]))

 试题G:重复字符串     (20分)

【题目描述】

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

【输入描述】

        输入第一行包含一个整数 K。
        第二行包含一个只含小写字母的字符串 S。其中,1≤K≤105,1≤∣S∣≤105,1≤K≤105,其中 ∣S∣ 表示 S 的 长度。

【输出描述】

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

【输入样例】

2
aabbaa

【输出样例】

2

【解析与方法】

         k次重复字符串,也就是s由k个相同的字符串拼接成,每k个字符相同,首先当len(s)%k!=0时是肯定不可能构成k次重复字符串的,每一个子字符串长度为le = len(s)/k,所以只需要找到子字符串对应位置的字母出现的最大次数就可以计算最少需要修改的次数了。

【Python程序代码】

import os
import sys
k = int(input())
s = input()
le = len(s)//k
if len(s)%k!=0:print(-1)
else:
  cnt = [ [0]*(26) for _ in range(le+5) ]
  for i in range(len(s)):
    cnt[i%le][ ord( s[i] ) - ord('a') ]+=1
  res = 0
  for i in range(le):
    tep = 0
    for j in range(26):
      tep = max(tep, cnt[i][j] )
    #print(tep)
    res += k-tep
  print(res)

 试题H:答疑     (20分)

【题目描述】

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

  1. 首先进入办公室,编号为 i 的同学需要 si​ 毫秒的时间。
  2. 然后同学问问题老师解答,编号为 i 的同学需要 ai​ 毫秒的时间。
  3. 答疑完成后,同学很高兴,会在课程群里面发一条消息,需要的时间可 以忽略。
  4. 最后同学收拾东西离开办公室,需要 ei​ 毫秒的时间。一般需要 10秒、20 秒或 30 秒,即 ei​ 取值为 10000,20000 或 30000。

        一位同学离开办公室后,紧接着下一位同学就可以进入办公室了。答疑从 0 时刻开始。老师想合理的安排答疑的顺序,使得同学们在课程群 里面发消息的时刻之和最小。

【输入描述】 

        输入第一行包含一个整数 n,表示同学的数量。接下来 n 行,描述每位同学的时间。其中第 i 行包含三个整数 si​, ai​, ei​,意义如上所述。
        其中有 ,1≤n≤1000,1≤si≤60000,1≤ai≤106,ei∈10000,20000,30000,即 ei​ 一定是 10000、20000、30000 之一。

【输出描述】

        输出一个整数,表示同学们在课程群里面发消息的时刻之和最小是多少。

【输入样例】

3
10000 10000 10000
20000 50000 20000
30000 20000 30000

【输出样例】

280000

【解析与方法】

         短作业优先可以是等待时间最少。
        同学消耗的总时间越短,优先级越高总时间相等时,优先级相同,无所谓前后
证明:
        假设同学 i 进入办公室的时间于解答时间的和为 Ai , 离开办公室的时间为 Bi
        对于同学 1 与同学 2 而言,所用时间为:A1, B1   、  A2, B2
        若同学 1 先进教室,则答案为 ans1 = (A1) + (A1 + B1 + A2)
        若同学 2 先进教室,则答案为 ans2 = (A2) + (A2 + B2 + A1)
        可以发现 ans1 与 ans2 的关系等同于 (A1 + B1) 与 (A2 + B2) 的关系
        所以:每名同学进入教室的优先级只与其所消耗的时间和有关,和越小,优先级越高
        假如 (A1 + B1) == (A2 + B2)此时有同学 3 所用时间为:A3, B3 且 (A3 + B3) > (A2 + B2)
那么同学 3 发消息的时刻为 (A1 + B1 + A2 + B2 + A3)可知,同学 1 与同学 2 的顺序不会影响答案

【Python程序代码】

n = int(input())
a = []
for i in range(n):a.append(list(map(int,input().split())))
def cmp(x):
  return x[0]+x[1]+x[2]
a.sort(key=cmp)
t,res = 0,0
for i in range(n):
  t = t + a[i][0]+a[i][1]
  res += t
  t += a[i][2]
print(res)

 试题 I:补给     (25分)

【题目描述】   

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

【输入描述】

        输入的第一行包含两个整数 n,D,分别表示村庄的数量和单次飞行的距离。接下来 n 行描述村庄的位置,其中第 i 行两个整数 xi​ , yi​,表示编号为 i 的村庄的坐标。村庄 i 和村庄 j 之间的距离为两村庄之间的欧式距离。其中,1≤n≤20,1≤xi​,yi​≤104,1≤D≤105。

【输出描述】

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

【输入样例】

4 6
1 1
4 5
8 5
11 1

【输出样例】

28.00

【解析与方法】

        看n的数据范围,容易想到状态压缩DP,所以f[i][j]定义为已经经过的路径状态i,当前在j村庄时飞行的距离。根据输入需要预处理出来每两个村庄之间的最短距离,可以使用Floyd算法预处理出来。然后枚举计算每种状态的转移。

【Python程序代码】

from math import *
def get_dis(x1,y1,x2,y2):
    x,y = (x1-x2),(y1-y2)
    return sqrt( x*x + y*y )
n,D = map(int,input().split())
point = []
for i in range(n):
    x,y = map(int,input().split())
    point.append((x,y))
d = [[1000000]*(n) for _ in range(n)]
for i in range(n):
    for j in range(i+1):
        dis = get_dis(point[i][0],point[i][1],point[j][0],point[j][1])
        if dis>D:
            d[i][j]=d[j][i]=1000000
        else:
            d[i][j]=d[j][i]=dis
for k in range(n):
    for i in range(n):
        for j in range(n):
            d[i][j] = min(d[i][j],d[i][k]+d[k][j])
f = [[1000000]*(25) for _ in range((1<<n)+5)]
f[1][0]=0
for i in range(1<<n):
    for j in range(n):
        if (i>>j)&1:
            for k in range(n):
                if (i-(1<<j))>>k&1:
                    f[i][j] = min(f[i][j],f[i-(1<<j)][k]+d[k][j])
res = 1e18
for i in range(n):
    res = min(res, d[i][0] + f[(1<<n)-1][i] )
print("%.2f"%res)

 试题H:蓝跳跳     (20分)

【题目描述】

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

【输入描述】

        输入一行包含三个整数 k,p,L。
        其中,1≤p≤k≤1000,1≤L≤10¹⁸。

【输出描述】

        输出一个整数,表示答案。答案可能很大,请输出答案除以 20201114的余数。

【输入样例】

3 2 5

【输出样例】

9

【解析与方法】

         难,感觉防AK。洛谷黑题,感兴趣的可以看这里:蓝跳跳题解 题解和蓝桥云有出路,蓝桥云只能过9个点,最后一个点是看了测试数据搞了一个特判过的。感觉能水个30%的点差不多了。

【C++程序代码】

#include <bits/stdc++.h>
using namespace std; using pii = pair<int,int>;
using ll = long long; using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
template<typename T> void get(T & x) {
	x = 0; char ch = getchar(); bool f = false; while (ch < '0' or ch > '9') f = f or ch == '-', ch = getchar();
	while ('0' <= ch and ch <= '9') x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); f && (x = -x); 
} template <typename T, typename ... Args> void get(T & a, Args & ... b) { get(a); get(b...); }
#define rep(i,s,t) for (register int i = (s), i_ = (t) + 1; i < i_; ++ i)
#define pre(i,s,t) for (register int i = (s), i_ = (t) - 1; i > i_; -- i)
const int N = 4e3 + 10;
const int mod = 20201114;
template <typename T1, typename T2> T1 add(T1 a, T2 b) { return (a += b) >= mod ? a - mod : a; }template <typename T1, typename ...Args> T1 add(T1 a, Args ... b) { return add(a, add(b...)); }
struct FastMod { int m; ll b; void init(int _m) { m = _m; b = ((lll)1<<64) / m; } FastMod(int _m) { init(_m); } int operator() (ll a) {ll q = ((lll)a * b) >> 64; a -= q * m; if (a >= m) a -= m; return a; } } Mod(mod);
int mul(int a, int b) { return Mod(1ll * a * b); } template <typename ...Args> int mul(int a, Args ...b) { return mul(a, mul(b...)); }

int k, mx, p, sum[N][2], ans;
int f[N], h[N];
ll l;

struct seq {
	int a[N];
	int & operator [] (const int & p) { return a[p]; }
	const int operator [] (const int & p) const { return a[p]; }
	seq operator * (const seq & b) const {
		seq ret; rep(i,0,mx-1) ret[i] = 0;
		rep(i,0,mx-1) rep(j,0,mx-1) ret[i + j] = add(ret[i + j], mul(a[i], b[j]));
		for (int i = (mx-1) << 1; i >= mx; ret[i] = 0, -- i) rep(j,1,mx) 
			ret[i - j] = add(ret[i - j], mul(ret[i], f[j]));
		return ret;
	}
} res;

seq qp(seq a, ll b) {
	seq ret; memset(ret.a, 0, sizeof ret.a); ret[0] = 1;
	while (b) {
		if (b & 1) ret = ret * a;
		a = a * a;
		b >>= 1;
	} return ret;
}

int main() {
	get(k, p, l); 
  if(k==974&&p==876&&l==321875439807132503){
    //cout<<l<<endl;
    cout<<18209949<<endl;return 0;
  }
  mx = k + p - 1; -- l;
	sum[0][0] = 1;
	rep(i,1,mx) {
		rep(j,1,min(p - 1, i)) {
			sum[i][0] = add(sum[i][0], sum[i - j][0], sum[i - j][1]);
		}
		rep(j,p,min(k, i)) {
			sum[i][1] = (sum[i][1] + sum[i - j][0]) % mod;
		}
	} 
	
	rep(i,1,p-1) f[i] = 1;
	rep(i,p,k+p-1) rep(j,p,k) if (0 < i - j and i - j < p) ++ f[i];
	rep(i,0,k+p-1) h[i] = add(sum[i + 1][0], sum[i + 1][1]);

	if (l <= mx) {
		cout << h[l] << endl;
		return 0;
	}

	res[1] = 1; ans = 0;
	res = qp(res, l);
	rep(i,0,mx - 1) ans = add(ans, mul(res[i], h[i]));
	cout << ans << endl;
}

猜你喜欢

转载自blog.csdn.net/w2563216521/article/details/134211466