2022年第十三届蓝桥杯大赛湖南中医药大学第2场选拔赛(部分总结)

文章目录

  • 2008: 简单整数问题
  • 2005: 飞行棋
  • 2074: 几乎回文串
  • 2101: 通行密令
  • 2089: 密码
  • 1867: X星救援站
  • 2085: 千里走单骑
  • 2093: 最长等比子序列
  • 2087: 跳水比赛
  • 总结

2008: 简单整数问题

[命题人 : admin]
时间限制 : 1.000 sec 内存限制 : 128 MB
题目描述
小明最近经常会思考一些关于整数的问题。今天他想到这么一个问题:
现在有n个整数,其中有些整数相同,也有一些整数不相同。首先需要找出其中出现次数最多的整数,如果出现次数最多的整数不唯一,则找出其中值最大的整数,记为M;然后再找出其中出现次数最少的整数,如果出现次数最少的整数不唯一,则找出其中值最小的整数,记为N;最后计算M和N的差,即输出(M-N)。
请你编写一个程序帮助小明解决这个问题。
输入
单组输入。
第1行包含一个正整数n,表示输入的整数个数。(n<=10^5)
第2行包含n个整数,两两之间用空格隔开。
输出
针对每一组输入,请按照题目的要求输出(M-N)。
样例输入 Copy
10
1 2 1 3 5 4 2 1 3 3
样例输出 Copy
-1
代码:

while True:
    n=int(input())
    k=list(map(int,input().split()))
    s=list(set(k))
    w=[]
    s.sort(reverse=True)
    for i in range(len(s)):
           w.append(k.count(s[i]))
    max1=s[w.index(max(w))]
    s.sort(reverse=False)
    w=[]
    for i in range(len(s)):
        w.append(k.count(s[i]))
    min1=s[w.index(min(w))]
    print(max1-min1)

2005: 飞行棋

[命题人 : admin]
时间限制 : 1.000 sec 内存限制 : 128 MB

题目描述
小明最爱飞行棋,今天他又和小花一起玩了很久飞行棋。玩着玩着,小明突然想到这么一个问题:
如果有一条长度为N的飞行棋棋盘(即棋盘中包含N个小格子),飞机的初始位置为第1个格子。每次投掷一次骰子,根据骰子的点数来决定可以前进的格数,例如骰子点数为1时可以前进1格,骰子点数为2时可以前进2格,……。骰子是一个正方体,六个面的点数分别是1、2、3、4、5、6。
假设最后一次投掷可以保证飞机刚好到达第N格。那么,请问从第1格到达第N格一共有多少种不同的投掷骰子的方法?
输入
单组输入,每组输入一个正整数N表示飞行棋棋盘所包含的格子数(1<=N<=10^3)。
输出
输出满足要求的投掷骰子的方法数。(结果对1e9+7取模)
样例输入 Copy
4
样例输出 Copy
4
提示
在样例中,飞行棋棋盘一共4格,则投掷骰子的点数和为3,3的组成方式有四种,分别是3=3,3=1+2,3=2+1,3=1+1+1,因此结果为4。
分析:
类似与上楼梯的问题和斐波那契数组的应用
代码:

s=[0,1,2,4,8,16,32]
def f():
    for i in range(7,1009):
        s.append((s[i-1]+s[i-2]+s[i-3]+s[i-4]+s[i-5]+s[i-6])%(1000000007))
while True:
    f()
    n=int(input())
    print(s[n-1])

2074: 几乎回文串

[命题人 : admin]
时间限制 : 1.000 sec 内存限制 : 128 MB

题目描述
小米同学很喜欢回文串。回文串就是从左往右读和从右往左读都一样的字符串,例如“ABCBA”或者“ABCCBA”。
基于回文串,爱思考的小米提出了“几乎回文串”。
那么,什么是几乎回文串呢?“几乎回文串”就是一个最多只需要修改1个字符就可以变成回文串的字符串。如果一个字符串本身就是一个回文串,当然也是一个“几乎回文串”。
例如:“ABCCDA”,虽然它不是一个回文串,但是它是一个几乎回文串,因为只需要把其中的“D”改为“B”或者把"B"改为“D”就可以构成一个回文串。
现在有一个全部都是大写英文字母的字符串,请你编写一个程序,判断这个字符串是不是一个“几乎回文串”?
输入
多组输入。
每行输入一个长度为N(1<=N<=1000)的全部由大写英文字母组成的字符串。
输出
对于输入数据中的每一行,如果是一个“几乎回文串”输出“Yes”,如果不是则输出“No”。
样例输入 Copy
ABCCDA
ABCCBA
ABCDCBB
ABCDE
ABBCC
样例输出 Copy
Yes
Yes
Yes
No
No

def huiwen(s)://判断回文
    ind=len(s)
    flag=0//记录有几个不同的
    if ind%2==0:长度为偶数
       for i in range(len(s)//2):
          if s[i]!=s[len(s)-1-i]:
              flag+=1
              if flag>1://超过一个不同的就返回-1结束
                  return -1
    else://长度为奇数
        for i in range((len(s)+1)//2):
            if s[i] != s[len(s) - 1 - i]:
                flag += 1
                if flag > 1:
                    return -1
    return 1
while True:
    s=list(input().strip())
    if huiwen(s)==1:
        print('Yes')
    else:
        print('No')

2101: 通行密令

[命题人 : admin]
时间限制 : 1.000 sec 内存限制 : 128 MB

题目描述
X星最近来了很多间谍,为此,X星总部加强了对进入总部大楼人员的检查,其中有一项检查为核实通行密令。
X星安检人员有一个密令文件,密令文件是一个只包含大写字母的字符序列。对于想进入总部大楼的人,首先需要提供一个口令,该口令也是一个只包含大写字母的字符序列。如果删除密令文件中若干个元素后可以得到该口令,则是一个合法口令,验证通过;否则将不允许进入总部大楼,且会被列入疑似间谍名单。
现在需要编写一个程序来判断某个口令是否合法。
输入
单组输入,每组输入包含两行。
第1行是一个长度不超过1000且全部由大写字母组成的字符序列,表示密令文件。
第2行是一个长度不超过100且也全部由大写字母组成的字符序列,表示用户口令。
输出
如果是一个合法口令,输出“Accept”,否则输出“Reject”。
样例输入 Copy
ABCDEFGH
ADEH
样例输出 Copy
Accept
代码:

k=list(input())
k1=list(input())
n=len(k1)
count=0
i=0
while True:
      if k1[i]==k[0]://一个一个对比,如果相等就加一然后去掉,不相等直接去掉。
          count+=1
          i+=1
          del k[0]
      else:
          del k[0]
      if len(k)==0:
          break
      if i==n:
          break
if n==count:
    print("Accept")
else:
    print("Reject")

2089: 密码

[命题人 : admin]
时间限制 : 1.000 sec 内存限制 : 128 MB
题目描述
Kimi买了一台新电脑,他给新电脑设置了一个开机密码。
这个开机密码跟一个数字N有关,具体产生过程如下:
(1) 数字N是一个合数(合数是指在大于1的整数中除了能被1和本身整除外,还能被其他数(0除外)整除的数,最小的合数为4)。将N分解质因子后变成几个质数相乘的形式。
(2) 将N的所有质因子按照从小到大的次序排列并连接在一起变成一个正整数M。例如:合数20的质因子为2、2和5,因此按照从小到大的次序将质因子连在一起得到M为225。
(3) 如果M的长度超过8位,则截取前面八位(高八位);如果M的长度不够8位,则在后面(低位)补0凑齐八位。例如:225不足八位,则在后面补5个0凑齐八位,变为22500000。
最终得到的这个八位正整数即为Kimi新电脑的密码。
现在给你一个N,你能否编写一个程序来破解Kimi新电脑的密码。

输入
单组输入。
输入一个合数N,N<=10^6。
输出
输出破解之后的8位数字密码。
样例输入 Copy
20
样例输出 Copy
22500000
分析:常规思路,暴力求因数

import math
s=[2]
def factor():
    for t in range(3,int(math.sqrt(1000009))*10):
        flag=1
        for i in range(2,int(math.sqrt(t))+1):
            if t%i==0:
                flag=0
                break
        if flag:
           s.append(t)
while True:
    factor()
    k=[]
    m=int(input().strip())
    i=0
    while m!=1:
       if m%s[i]==0:
           k.append(s[i])
           m=m//s[i]
           continue
       i+=1
    z=""
    for t in k:
       z+=str(t)
    if len(z)<8:
        z=z+ '0'*(8-len(k))
    if len(z)>8:
        z=z[:8]
    for t in z:
        print(t,end="")
    print()

1867: X星救援站

[命题人 : admin]
时间限制 : 1.000 sec 内存限制 : 128 MB
题目描述
X星是宇宙中一个非常敬畏生命和热爱生命的星球。在X星上建有一个规模很大而且设备很先进的救援站。
为了方便救援工作的开展,X星规定,任意两点之间的一条道路出现问题,都不会完全切断救援站和居民点的通路。也是说救援站到其他顶点都有两条或者两条以上的路线,而且其中某条路线中的一条边出现断开时,至少还可以找到另一条完整的通路。这样在救援过程中,即使某一条路线出现问题,还可以通过其他路线到达目的地。
已知救援站和部分居民点之间,以及某些居民点之间有直接的道路相连(所有的道路都是双向的)。
现在请你编写一个程序,根据给出的救援站和居民点之间,以及某些居民点之间的连接信息,判断每一组输入数据是否满足X星的规定。如果满足规则请输出“Yes”,否则输出“No”。
输入
多组输入,第1行输入一个正整数T表示输入数据的组数。
对于每一组输入数据:
第1行输入两个正整数N和M,其中N表示救援点和居民点的数量,对应N个顶点。其中编号为1的顶点表示救援点,编号为2到N表示(N-1)个居民点。M表示救援站和居民点之间,以及某些居民点之间的道路连接信息的数量。(N<=1000,M<=100000)
接下来M行每行包含两个正整数,分别为相邻的两个顶点(救援点或者居民点)的编号,两个正整数之间用空格隔开。
输出
针对每一组输入数据,如果输入数据满足X星的规定,任意一条道路的断开都不会影响到救援站到居民点之间的连通性,输出“Yes”,否则输出“No”。
样例输入 Copy
2
4 4
1 2
2 3
3 4
4 1
4 4
1 2
2 3
3 4
1 3
样例输出 Copy
Yes
No
分析:
这道题目涉及了双连通分量问题,可以用tarjan算法,建议用C++写,Python一直运行错误。如果整个图是一个强连通图,那救援站到居民的路径一定不止一条,把图建好之后,用tarjan算法,得到强连通分量的数量,如果是1,输出yes,否则输出no。因为图比较大,可以用数组模拟邻接表来建图
代码:

#include
#include
#include
#include
#include
using namespace std;
const int N = 10010,M=200010;
int h[N], e[M], ne[M], idx;
int n, m;
int dfn[N], low[N], timestamp;
int stk[N], top;
int dcc_cnt;
void add(int a, int b)//数组模拟邻接表来建图
{
    e[idx] = b,ne[idx] = h[a], h[a] = idx++;
}

void tarjan(int u, int from)//tarjan模板
{
    dfn[u] = low[u] = ++timestamp;
    stk[++top] = u;
    for (int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (!dfn[j])
        {
            tarjan(j, i);
            low[u] = min(low[u], low[j]);
        }
        else if (i != (from ^ 1))
            low[u] = min(low[u], dfn[j]);
    }
    if (dfn[u] == low[u])
    {
        ++dcc_cnt;
        int y;
        do {
            y = stk[top--];
        } while (y != u);
    }
}
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        memset(h, -1, sizeof h);
        memset(dfn, 0, sizeof dfn);
        memset(stk, 0, sizeof stk);
        memset(low, 0, sizeof low);
        top = timestamp = 0;
        dcc_cnt = 0;
        cin >> n >> m;
        while (m--)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            add(a, b), add(b, a);
        }
        for (int i = 1; i <= n; i++)
        {
            if (!dfn[i])
                tarjan(i, -1);
        }
        if (dcc_cnt > 1)
            printf("No\n");
        else
            printf("Yes\n");
    }
    return 0;
}

2085: 千里走单骑

[命题人 : admin]
时间限制 : 1.000 sec 内存限制 : 128 MB
题目描述
程序员Kimi同学这几天在看《三国演义》。今天他看到了“千里走单骑”这一回。
话说关羽带领很少的士兵护送刘备的两位夫人离开曹操去找刘备,一路上过五关、斩六将,费尽千辛万苦终于见到了刘备。
一边看,Kimi一边在思考这么一个问题:
假设一共有N个点表示N个城池,这N个城池的编号分别为1、2、…N。关羽的起点为1号城池,终点为N号城池。
关羽现在要从1号城池前往N号城池,中间需要经过若干城池,当然也存在若干条路径。
除了第1个和最后1个城池外,其他城池都有敌军把守,关羽需要一些时间来打败每一个城池的敌军。
现在告诉我们关羽行走在两个相邻城池之间所需的时间,还告诉我们关羽打败每一个城池的敌军所需时间。
请编写一个程序,求出关羽从第1号城池到第N号城池所需的最少时间。
输入
单组输入。
第1行输入两个正整数N和M,其中N表示城池个数,M表示有多少对相邻的城池。N<=100,M<=1000。N和M之间用英文空格隔开。
第2行输入N个非负整数分别表示关羽打败每一个城池的敌军所需时间,第1个和第N个数为0。两两之间用英文空格隔开。
接下来M行每行包含三个正整数,前两个正整数表示两个相邻城池的编号,编号小的在前,编号大的在后,第三个正整数表示关羽行走在两个相邻城池之间所需的时间。两两之间用英文空格隔开。
【输入数据保证可以构建一个连通的无向图,从第1号城池到第N号城池之间至少存在一条路径。】
输出
输出一个正整数,表示关羽从第1号城池到第N号城池所需的最少时间。
样例输入 Copy
4 4
0 2 6 0
1 2 3
2 4 2
1 3 2
3 4 1
样例输出 Copy
7
分析:将攻打a城池的时间算到路径c->a的时间里面,然后再用flyod算法和dijistra算法,前者时间复杂度为你n3但是理解起来简单适应于求矩阵最短路径,元素可以是负权值,数量级为200到300;后者为n2适用于单源最短路径问题,权值不能为负数.
代码:
floyd算法:

while True:
    n, m = map(int, input().strip().split())
    time = list(map(int, input().split()))
    s = [[float('inf') for i in range(n)] for i in range(n)]
    s[0][0] = 0
    for i in range(m):
        x, y, z = map(int, input().split())//攻打城池的时间给到路径上
        s[x - 1][y - 1] = z + time[y - 1]
        s[y - 1][x - 1] = z + time[x - 1]
    for k in range(n):
        for i in range(n):
            for j in range(n):
                if s[i][k] + s[k][j] < s[i][j]:
                    s[i][j] = s[i][k] + s[k][j] 
    print(s[0][n - 1])

dijistra算法:

def dijkstra():
    global closeid, closedistance
    used = [0 for i in range(n)]
    closedistance = [float('inf') for i in range(n)]
    closedistance[0]=0
    closeid = [0 for i in range(n)]
    for i in range(1,n):
        closedistance[i] = s[0][i]
    used[0] = 1
    for i in range(1,n):
        j = -1
        for k in range(n):
            if used[k] == 0 and (j==-1 or closedistance[j] > closedistance[k]):
                j = k
        used[j] = 1
        for k in range(n):
            if closedistance[j] + s[j][k] < closedistance[k]:
                closedistance[k] = closedistance[j] + s[j][k]
                closeid[k] = j
                s[j][k] -= time[k]//攻打完了,此城池时间要减去
while True:
    n, m = map(int, input().strip().split())
    time = list(map(int, input().split()))
    s = [[float('inf') for i in range(n)] for i in range(n)]
    for i in range(m):
        x, y, z = map(int, input().split())
        s[x - 1][y - 1] = min(s[x - 1][y - 1], z + time[y - 1])
        s[y - 1][x - 1] = min(s[y - 1][x - 1], z + time[x - 1])
    dijkstra()
    print(closedistance[n - 1])

在这里插入图片描述

2093: 最长等比子序列

[命题人 : admin]
时间限制 : 2.000 sec 内存限制 : 128 MB
题目描述
给定一个由N个正整数组成的整数序列,从中选取若干个元素构成一个等比子序列。
子序列就是在原序列中删除若干元素后所得到的序列,子序列中相邻两个元素在原序列中不要求一定相邻,例如序列(1,3,5)是序列(1,2,3,4,5)的子序列之一。
等比子序列就是在一个子序列中,所有的元素构成一个等比数列,例如(1,3,9,27)或者(1,1,1,1,1)或者(8,4,2,1)。
请编写一个程序找出输入序列的最长等比子序列,输出最长等比子序列的长度。
输入
单组输入。
第1行输入一个正整数N,表示正整数序列中包含的数字个数,N<=1000。
第2行输入N个正整数,两两之间用空格隔开。
输出
输出最长等比子序列的长度。
样例输入 Copy
10
1 3 2 5 4 2 8 6 16 9
样例输出 Copy
5
提示
输入样例中存在最长等比子序列1,2,4,8,16,其长度为5。
分析:利用类似于求最长等差子序列。
代码:

while True:
    n = int(input())
    s = list(map(int, input().split()))
    dp = [{} for i in range(n)]
    max1 = 0
    flag = 1
    for i in range(1, n):
        for j in range(i):
            flag = s[i] / s[j]
            if flag not in dp[j]:
                dp[i][flag] = 2
            else:
                dp[i][flag] = dp[j][flag] + 1
            max1 = max(max1, dp[i][flag])
    print(max1)

2087: 跳水比赛

[命题人 : admin]
时间限制 : 1.000 sec 内存限制 : 128 MB
题目描述
一年一度的X星跳水锦标赛开始啦!
现在正在进行的是男子十米跳台比赛,一共有N个选手参赛,每一个选手需要比赛六轮。
现已经按照出场顺序给出每一位选手的姓名和六轮跳水比赛的成绩,每一个成绩均保留两位小数。
竞赛组委会需要按照成绩对姓名进行排序,排序规则如下:
(1) 首先按照六轮总分由高到低降序排列。
(2) 如果两名或多名选手的总分相同,则按照最后一轮得分由高到低降序排列(假设最后一轮的难度最大)。
(3) 如果两名或多名选手的总分相同且最后一轮得分也相同,则按照原始的出场顺序排列,即按照初始输入的顺序。
请编写一个程序对跳水比赛的结果进行排序,输出排序之后的选手姓名。
输入
单组输入。
第1行输入一个正整数N表示选手的总人数,N<=1000。
从第2行到第N+1行,每行输入一名选手的姓名以及他六轮比赛的成绩,两两之间用英文空格隔开,成绩保留两位小数。

输出
输出按照规则排序之后的结果,每行输出一名选手的姓名。
样例输入 Copy
3
Tim 90.00 92.15 88.74 100.00 90.00 88.45
Bob 90.00 92.15 88.74 100.00 92.00 86.45
Kimi 100.00 100.00 100.00 100.00 100.00 100.00
样例输出 Copy
Kimi
Tim
Bob
分析:常规排序问题:
代码:

while True:
    n=int(input())
    s=[[] for i in range(n)]
    for i in range(n):
        s[i]=list(map(str,input().split()))
        for j in range(1,7):
                s[i][j]=float(s[i][j])
        s[i].append(sum(s[i][1:]))
        s[i].append(i)
    
    s.sort(key=lambda x:(x[7],x[6],-x[8]),reverse=True)
    for t in s:
        print(t[0])

总结

用于学习记录,有不好的地方,望大佬指教,第一个素数圈用Python运行错误就没有贴了,谢谢。

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