yanchang
yanchang
发布于 2026-06-05 / 9 阅读
0
0

第十六届蓝桥杯大赛软件赛国赛Python 研究生组A~G

A

问题描述

已知一个长方形的面积为 2025,且其长和宽均为正整数。现在,请你计算这个长方形可能的最大周长是多少。

答案提交

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

运行限制

语言

最大运行时间

最大运行内存

C++

1s

256M

C

1s

256M

Java

2s

256M

Python3

3s

256M

PyPy3

3s

256M

Go

3s

256M

JavaScript

3s

256M

分析

直接暴力即可

import os
import sys

# 请在此输入您的代码
n=2025
maxc=0
for i in range(1,2025):
  if 2025%i==0:
    maxc=max(2*(i+2025//i),maxc)
print(maxc)

B

问题描述

在潮声渐起的码头边,信号工程师小蓝负责维护一套由 2025 盏信号灯组成的系统。这些灯排成一列,每盏灯可以亮起或熄灭,共有 22025 种可能的初始排列。为了测试系统的稳定性,小蓝设计了一个实验:他会选定一种初始排列,然后执行 2026 次独立的状态切换操作——即改变灯的状态(亮变灭,灭变亮)。具体地:

  • 1 次操作:不对任何灯进行切换,保持初始状态不变。

  • 2次操作:切换最左侧 1 盏灯的状态。

  • 3次操作:切换最左侧 2 盏灯的状态。

  • ⋯⋯

  • 2025 次操作:切换最左侧 2024 盏灯的状态。

  • 2026 次操作:切换所有灯的状态。

每次操作后,小蓝会记录亮着的灯的数量,然后将灯的状态恢复到选定的初始排列,再进行下一次操作。

小蓝发现:对于某些特定的初始排列,在这 2026 次操作所记录到的亮灯数量,只会有三种不同的值,即每次操作后的亮灯数量只会在三个值之间变化,不会出现第四个不同的值。

对此,小蓝想知道,在这 22025 种可能的初始排列中,有多少种初始排列能使这 2026 次操作所记录到的亮灯数量恰好有三种不同值,请帮助他计算这个数量。由于答案可能很大,你只需给出其对 109+7 取余后的结果即可。

答案提交

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

C

问题描述

能源公司正着手建立新的基地。

为了确保基地的能源供应,公司计划铺设一条长度至少为 N 公里的能源管道。铺设管道的成本并非简单地与管道长度成正比,而是由管道长度的各位数字之和决定。例如,铺设长度为 123 公里的管道,实际成本为 1+2+3=6

为了尽可能降低成本,公司希望找到一个长度为 M 公里的铺设方案,使得 M 不小于 N,并且 M 的数位和最小。如果存在多个满足条件的 M,则选择数值最小的方案,以确保在成本相同的情况下,尽可能减少资源浪费。

现在,请你帮助能源公司计算出最优的管道铺设长度 M

输入格式

输入一个整数 N,表示需要铺设的最低管道长度。

输出格式

输出一个整数 M,表示最优的管道铺设长度。

样例输入

9

样例输出

10

评测用例规模与约定

对于 30% 的评测用例,1≤N≤100

对于所有的评测用例,1≤N≤109

分析

如果要数位和最小,那么简单了,就是10的若干次方呗、1、10、100、1000 ............找到一个比N大的即可

import os
import sys
N=int(input())
M=1
while(M<N):
  M*=10
print(M)

D

问题描述

在信息检索系统中,倒排索引是一种常用的数据结构,用于快速查找包含特定词语的文档集合。为了增强搜索的灵活性,我们引入了 N-Gram 分词算法,参数 [min,max],表示分别按照长度 min,min+1,⋯,max 对单词进行滑动窗口截取。例如对于 [3,5] 的 N-Gram,会将单词 langb 分割为 [lan, anq, nqb, lang, anqb, lanqb] 的索引序列,如果文档长度小于 min,那么索引序列只包含文档本身。

给定 n 个文档,对于第 i 个文档 di,利用上述的 N-Gram 算法为其生成一组索引序列 Li。对于查询词 q,也对其应用 N-Gram 为其生成一个索引序列 P,如果序列 P 中的某个单词出现在序列 Li 中,那么就认为查询词和文档 di 匹配成功。

请统计查询词 q 能与多少个文档匹配成功。

输入格式

输入的第一行包含三个正整数 n,min,max,相邻整数之间使用一个空格分隔。

接下来 n 行,每行包含一个字符串,其中第 i 行的字符串表示文档 di

接下来一行包含一个字符串,表示查询词 q

输出格式

输出一行包含一个整数表示答案。

样例输入

3 3 4
angel
ac
angle
lang

样例输出

2

样例说明

文档分词结果如下:

  • angel: [ang, nge, gel, ange, ngel]

  • ac: [ac]

  • angle: [ang, ngl, gle, angl, ngle]

查询词分词结果如下:

  • lang: [lan, ang, lang]

angelangle 的分词中都包含 ang,所以答案为 2。

评测用例规模与约定

s 表示字符串 ss 的长度。

对于 50% 的评测用例,1n100

对于所有评测用例,1⩽n⩽1031minmax201di∣,∣q20diq 都只包含小写英文字母。

分析

import os
import sys

def get_ngrams(s, min_, max_):
    # 特殊边界:长度小于 min,则只包含自身
    if len(s) < min_:
        return {s}
    
    ngrams = set()
    # 正常进行 N-Gram 切片
    for d in range(min_, max_ + 1):
        for j in range(len(s) - d + 1):
            ngrams.add(s[j:j+d])
    return ngrams

def main():
    # 1. 读取第一行输入
    n, min_, max_ = map(int, input().split())
    
    # 2. 读取 n 个文档,并分别生成它们的分词集合
    documents_ngrams = []
    for _ in range(n):
        doc = input().strip()
        documents_ngrams.append(get_ngrams(doc, min_, max_))
        
    # 3. 读取查询词,并生成查询词的分词集合
    q = input().strip()
    q_ngrams = get_ngrams(q, min_, max_)
    
    # 4. 统计有多少个文档与查询词匹配成功
    match_count = 0
    for doc_set in documents_ngrams:
        # 使用 set 的 intersection (交集) 或 & 运算符
        # 只要交集不为空,说明至少有一个单词匹配成功
        if q_ngrams & doc_set:
            match_count += 1
            
    # 5. 输出答案
    print(match_count)

if __name__ == '__main__':
    main()

E

问题描述

小蓝手里有一个长度为 nn 的十进制正整数序列 (a1,a2,⋯,an),他希望修改这个序列中的一些数使其变为一个上升序列,即满足对于所有的 i2in,都有 ai−1<ai。他只能通过在这些正整数的十进制表示中增加数字 0 来构造这个上升序列,他想知道最少增加多少个 0 可以满足条件。

输入格式

输入的第一行包含一个正整数 nn

第二行包含 nn 个正整数 a1,a2,⋯,an,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个整数表示答案。

样例输入

6
527559 483873 913413 181072 822487 853172

样例输出

8

样例说明

其中一种方案,更改后的序列为 (527559, 4083873, 9013413, 10081072, 80022487, 85003172),共增加 8 个 0。

评测用例规模与约定

对于 20% 的评测用例,1n10

对于所有评测用例,1n50001ai106。增加 0 之后允许超过 106

分析

本质上就是一个贪心题目

def getnum(tag,i):
    nu=0
    if tag<int(i):
        return nu,int(i)
    else:
        l=0
        nu+=(len(str(tag))-len(i))
        while(l<min(len(i),len(str(tag))) and str(tag)[l]==i[l]):l+=1
        if str(tag)[l]==i[l]:
            nu+=1
            return nu,int(i+('0'*nu))
            pass
        elif str(tag)[l]<i[l]:
            return nu,int(i[0:l+1]+('0'*nu)+i[l+1:])
        else:
            nu+=1
            return nu,int(i[0:1]+('0'*nu)+i[1:]) 


n=int(input())
words=list(input().split())
tag=0
sums=0
for i in words:
    nu,tag=getnum(tag,i)
    sums+=nu
print(sums)

F

问题描述

小蓝正在二维坐标系中构造正方形,他手上有 n 个正整数 a1,a2,⋯,an,他想知道有多少个有序四元组 (i,j,p,q) 满足 i,j,p,qi,j,p,q 互不相同,且四个点:(0,0)(−ai,aj)(ap,aq)(apai,aj+aq) 能构成一个正方形?

输入格式

输入的第一行包含一个正整数 n

第二行包含 n 个正整数 a1,a2,⋯,an,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个整数表示答案。答案可能很大,请输出答案除以 1000000000+7109+7)的余数。

样例输入

15
1 1 1 1 2 2 1 2 2 2 1 1 1 1 1

样例输出

8760

样例说明

可用的数一共有 10 个 1 和 5 个 2。

  • ai=1,aj=2,ap=2,aq=1 时,有 A102A52=1800 种方案;

  • ai=2,aj=1,ap=1,aq=2 时,有 A102A52=1800 种方案;

  • ai=1,aj=1,ap=1,aq=1 时,有 A104=5040 种方案;

  • ai=2,aj=2,ap=2,aq=2 时,有 A54=120 种方案;

总共有 8760 种方案。

评测用例规模与约定

对于 40% 的评测用例,1⩽n⩽1001n100

对于所有评测用例,1⩽n⩽10000001n10000001⩽ai⩽10001ai1000

import os
import sys
from collections import Counter
n = int(input())
list1 = list(map(int,input().split()))
c = Counter(list1)
MOD = 10**9 + 7
ans = 0
list2 = list(c.values())
for i in range(len(list2)):
  if list2[i] >= 4:
    cur_ans = list2[i]*(list2[i] - 1) *(list2[i]-2)*(list2[i]-3)
    ans = (ans+cur_ans)%MOD
for i in range(len(list2)):
  if list2[i] < 2:
    continue
  for j in range(i+1,len(list2)):
      if list2[j] < 2:
        continue
      else:
        cur_ans = list2[i]*(list2[i]-1)*list2[j]*(list2[j]-1)
        ans = (ans + 2*cur_ans)%MOD
print(ans)

G

问题描述

网络安全团队需要开发一个系统来监控和检测恶意网络流量。他们收集了一系列已知的恶意请求路径模式,每个模式都有一个对应的风险等级。你的任务是实现一个算法,检测给定的网络请求路径是否匹配这些模式,并返回匹配模式中最高的风险等级。下面是恶意请求路径的相关描述:

路径格式

  • 路径由斜杠(/)分隔的若干段组成,如 /api/users/profile

  • 路径总是以斜杠(/)开头。

  • 路径中的每一段可以是由小写英文字母和数字组成的非空字符串。当路径为路径模式时,路径中的一段还可以是通配符 ***

通配符规则

  • 通配符包括单通配符(*)和双通配符(**),只能是路径模式中的完整一段。一个路径中最多有一段通配符,不能出现两个单通配符,不能出现两个双通配符,也不能同时出现单通配符和双通配符。

  • 单通配符(*)用于匹配路径中的任意一段。

    • 例如:/api/*/delete 可以匹配 /api/users/delete/api/files/delete,但不能匹配 /api/admin/users/delete

  • 双通配符(**)用于匹配路径中的零段或连续多段。

    • 例如:/api/admin/** 可以匹配 /api/admin/api/admin/users/api/admin/users/profile

    • 例如:/static/**/execute 可以匹配 /static/execute/static/js/execute/static/css/js/execute

风险评估

  • 每个恶意路径模式都有一个风险等级。

  • 如果一个请求同时匹配多个模式,返回风险等级最高的。

  • 如果不匹配任何模式,返回 SAFE

你需要实现一个算法,给定恶意请求路径模式集合和一系列网络请求路径,判断每个网络请求是否触发警报,并且返回触发的最高风险等级。

输入格式

输入的第一行包含一个正整数 n ,表示恶意路径模式的数量

接下来 n 行,每行包含一个整数 li 和一个字符串 pi ,用一个空格分隔,表示一个恶意请求路径模式,li 表示风险等级,pi 表示路径模式。

接下来一行包含一个整数 m ,表示要检测的网络请求数量。

接下来 m 行,每行包含一个字符串 qi ,表示一个网络请求路径。

输出格式

对于每个网络请求路径,输出一行,包含检测结果。如果触发警报,输出 ALERT: [风险等级];如果没有触发警报,输出 SAFE

样例输入

5
80 /api/admin/**
60 /api/*/delete
75 /*/config/system
90 /api/users/*/password
50 /static/**/execute
8
/api/users/profile
/api/admin/users
/api/config/delete
/dev/config/system
/static/js/execute
/api/users/123/password
/static/css/js/execute
/api/admin

样例输出

SAFE
ALERT: 80
ALERT: 60
ALERT: 75
ALERT: 50
ALERT: 90
ALERT: 50
ALERT: 80

样例说明

  1. /api/users/profile - 不匹配任何模式,所以是 SAFE。

  2. /api/admin/users - 匹配 /api/admin/**,风险等级 80。

  3. /api/config/delete - 匹配 /api/*/delete,其中 * 匹配 config,风险等级 60。

  4. /dev/config/system - 匹配 /*/config/system,其中 * 匹配 dev,风险等级 75。

  5. /static/js/execute - 匹配 /static/**/execute,其中 ** 匹配 js,风险等级 50。

  6. /api/users/123/password - 匹配 /api/users/*/password,其中 * 匹配 123,风险等级 90。

  7. /static/css/js/execute - 匹配 /static/**/execute,其中 ** 匹配 css/js,风险等级 50。

  8. /api/admin - 匹配 /api/admin/**,其中 ** 匹配空(0 个段),风险等级 80。

评测用例规模与约定

对于 20% 的评测用例,1≤n≤10,1≤m≤10

对于 40% 的评测用例,1≤n≤100,1≤m≤100

对于 60% 的评测用例,1≤n≤1000,1≤m≤1000

对于所有评测用例,1≤n≤10,0001≤m≤10001≤li≤500001≤∣pi∣≤501≤∣qi∣≤50

分析

import sys


def split_path(path):
    if path == b"/":
        return ()
    return tuple(path[1:].split(b"/"))
def update_max(table, key, level):
    old = table.get(key)
    if old is None or level > old:
        table[key] = level
def solve():
    data = sys.stdin.buffer.read().split()
    if not data:
        return
    pos = 0
    n = int(data[pos])
    pos += 1
    exact = {}
    single_wildcard = {}
    double_wildcard = {}
    for _ in range(n):
        level = int(data[pos])
        pattern = data[pos + 1]
        pos += 2

        parts = split_path(pattern)
        if b"**" in parts:
            idx = parts.index(b"**")
            key = (parts[:idx], parts[idx + 1 :])
            update_max(double_wildcard, key, level)
        elif b"*" in parts:
            idx = parts.index(b"*")
            key = (len(parts), idx, parts[:idx], parts[idx + 1 :])
            update_max(single_wildcard, key, level)
        else:
            update_max(exact, parts, level)
    m = int(data[pos])
    pos += 1
    ans = []
    for _ in range(m):
        parts = split_path(data[pos])
        pos += 1
        length = len(parts)

        best = exact.get(parts, 0)

        for idx in range(length):
            key = (length, idx, parts[:idx], parts[idx + 1 :])
            level = single_wildcard.get(key, 0)
            if level > best:
                best = level

        for prefix_len in range(length + 1):
            prefix = parts[:prefix_len]
            for suffix_len in range(length - prefix_len + 1):
                if suffix_len == 0:
                    suffix = ()
                else:
                    suffix = parts[length - suffix_len :]
                level = double_wildcard.get((prefix, suffix), 0)
                if level > best:
                    best = level
        if best:
            ans.append(f"ALERT: {best}")
        else:
            ans.append("SAFE")
    sys.stdout.write("\n".join(ans))

solve()


评论