蓝桥杯python练习题-13

 试题A:裁纸刀 本题总分:5分


【问题描述】
小蓝有一个裁纸刀,每次可以将一张纸沿一条直线裁成两半。
小蓝用一张纸打印出两行三列共6个二维码,至少使用九次裁出来,下图给出了一种裁法。
在上面的例子中,小蓝的打印机没办法打印到边缘,所以边缘至少要裁4次。另外,小蓝每次只能裁一张纸,不能重叠或者拼起来裁。
如果小蓝要用一张纸打印出20行22列共440个二维码,他至少需要裁多少次?

count=4
count+=19
count=count+(21*20)
print(count)

 答案是443

试题B:寻找整数 本题总分:5分


【问题描述】
有一个不超过10^17的正整数n,知道这个数除以2至49后的余数如下表所示,求这个正整数最小是多少。

(答案是2022040920220409,据说是当年考试日期。但是在网上没有看到什么好方法,好像可以用中国剩余定理解)

试题C:质因数个数 本题总分:10分


【问题描述】
给定正整数n,请问有多少个质数是n的约数。

【输入格式】
输入的第一行包含一个整数n。
【输出格式】
输出一个整数,表示n的质数约数个数。

 思路1:大佬的解法但是我没太看懂,能跑出80%的答案

import math

n=int(input())
count=[]#储存找到的质因数
def iszhi(n):#判断是否是质数
    flag=1
    for i in range(2,int(math.sqrt(n))+1):
        if n%i==0:
            count.append(i)#i是约数
            flag=0
            a=n//i
            break
    if flag==0:
        iszhi(a)
    else:#不能整除,则说明 n 本身是质数,将其加入 count 中
        count.append(n)
iszhi(n)
count=set(count)
print(len(count))

思路2:先筛选出小于n的所有素数,用的埃拉托斯特尼筛法,就是不断把一个素数的倍数标记为非素数,时间复杂度大致为 O(nloglogn),再判断是否是约数。

import math

n=int(input())
m=[True for i in range(n+1)]#比n小的所有质数
for i in range(2,int(math.sqrt(n))+1):
    if m[i]:
        t=i+i
        while t<n+1:
            m[t]=False
            t=t+i

count=0
for i in range(2,n+1):
    if n%i==0 and m[i]:#是约数和质数
        count+=1
print(count)

以下为错误代码(运行超时),因为每一次判断都进入了iszhi()函数中,(时间复杂度为n^2?)

import math
def iszhi(n):#判断是否是质数
    if n==2:
        return 1
    for i in range(2,int(math.sqrt(n))+1):
        if n%i==0:
            return 0
    return 1
n=int(input())
count=0
for i in range(2,n+1):
    if n%i==0 and iszhi(i):#是约数和质数
        count+=1
print(count)

 试题E:消除游戏 本题总分:15分


【问题描述】
在一个字符串S中,如果S;= Si-1且S;≠ S+1,则称S,和Si+1为边缘字符。如果Si≠ S-1且S;= S;1,则S-,和S;也称为边缘字符。其它的字符都不是边缘字符。
对于一个给定的串 s,一次操作可以一次性删除该串中的所有边缘字符(操作后可能产生新的边缘字符)。
请问经过264次操作后,字符串S变成了怎样的字符串,如果结果为空则输出EMPTY。
【输入格式】
输入一行包含一个字符串S 。

【输出格式】
输出一行包含一个字符串表示答案,如果结果为空则输出EMPTY。

 这段代码运行超时只拿了80%

n=list(input())
flag=0
length=0
for j in range(2**64):
    c=[]
    l=len(n)
    if len(n)<3:
        break
    if l==length:#如果已经没有可以删去的说明已经是最短的字符串了
        break
    for i in range(1,l-1):
        if n[i]==n[i-1] and n[i]!=n[i+1]:
            c.append(i)
            c.append(i+1)
        elif n[i]!=n[i-1] and n[i]==n[i+1]:
            c.append(i)
            c.append(i-1)
    c=list(set(c))
    c.sort(reverse=True)
    for k in c:
        del n[k]
    length=l
if len(n)==0:
    print("EMPTY")
else:
    for i in n:
        print(i,end="")

 骗分方法:print("EMPTY")能跑过几道测试

 试题F:重新排序 本题总分:15分


【问题描述】
给定一个数组A和一些查询L,R;,求数组中第L至第R;个元素之和。小蓝觉得这个问题很无聊,于是他想重新排列一下数组,使得最终每个查询结果的和尽可能地大。小蓝想知道相比原数组,所有查询结果的总和最多可以增加多少?
【输入格式】
输入第一行包含一个整数n。
第二行包含n个整数Ai,A2,… - ,A,相邻两个整数之间用一个空格分隔。第三行包含一个整数m表示查询的数目。
接下来m行,每行包含两个整数L、R,相邻两个整数之间用一个空格分隔。
【输出格式】
输出一行包含一个整数表示答案。

 运行超时,过了90%

import copy
n=int(input())
l=list(map(int,input().split()))
temp=copy.deepcopy(l)
temp.insert(0,0)#排列之前的
l.sort()#从小到大
m=int(input())
lr=[]
for i in range(m):
    lr.append(list(map(int,input().split())))
l.insert(0,0)
count=dict((i,0) for i in range(1,n+1))# 用字段储存每个数值被访问次数
for i in lr:
    for j in range(i[0],i[1]+1):
        count[j]+=1
new=[]
for i in count.keys():
    new.append((i,count[i]))#转化为元组
new.sort(key=lambda x:x[1],reverse=True)#以每个元素的第二项作为依据,对x从大到小排列
a=[0 for i in range(n+1)]#排列之后的
for i in range(n):
    temp1,temp2=new[i]#1是访问次数最多的数,2是访问次数
    temp3=l.pop()#移除最后一个元素
    a[temp1]=temp3
out=0
for i in range(m):#把m行的数加起来算
    out+=(sum(a[lr[i][0]:lr[i][1]+1])-sum(temp[lr[i][0]:lr[i][1]+1]))
print(out)

试题G:全排列的价值 本题总分:20分


【问题描述】
对于一个排列A= (a1,a2,… ,an),定义价值c为 a至a;-1中小于a;的数的个数,即 bi=l{alj <i,a;<a)。定义A 的价值为>”Ci。
给定n,求1至n的全排列中所有排列的价值之和。

【输入格式】
输入一行包含一个整数n 。

【输出格式】
输出一行包含一个整数表示答案,由于所有排列的价值之和可能很大,请输出这个数除以998244353的余数。

 思路:

以题中样例,当 n = 3
其中第一个顺序:1,2,3;它的价值为 3
它的倒序:3,2,1;它的价值为0

第二个顺序:1,3,2;它的价值为2
它的倒序:2,3,1;它的价值为1

第三个顺序:2,1,3;它的价值为2
它的倒序:3,1,2;它的价值为1

一个序列与它倒序价值和是固定值,即0+1+...+(n-1)=n(n-1)//2

所有排列情况为n*(n-1)*(n-2)*...*1=n!,把倒序的情况除掉即为n!//2

n = int(input())
num = 1
for i in range(1, n + 1):#n 个元素的所有排列的总数
    num *= i
ans = num // 2#除了倒序以外的排列情况
ans*= ((n - 1) * n // 2) #每种排列情况的价值
ans%= 998244353#取余
print(ans)

试题H:最长不下降子序列 本题总分:20分


【问题描述】
给定一个长度为N的整数序列:A,Az,… - ,A,。现在你有一次机会,将其中连续的K个数修改成任意一个相同值。请你计算如何修改可以使修改后的数列的最长不下降子序列最长,请输出这个最长的长度。
最长不下降子序列是指序列中的一个子序列,子序列中的每个数不小于在它之前的数。
【输入格式】
输入第一行包含两个整数N和K。第二行包含Ⅳ个整数Ay,Az,…- ,AN .
【输出格式】
输出一行包含一个整数表示答案。

 据说是最长上升子序列模板题,但是只跑通了20%,当个模板看

def check(lst):
    for i in range(1, len(lst)):
        if lst[i] < lst[i - 1]:
            return False
    return True

N, K = map(int, input().split())
numList = list(map(int, input().split()))
if check(numList):
    print(N)
else:
    dp = [1 for i in range(N)]
    for i in range(N):
        for j in range(i):
            if numList[i] >= numList[j]:
                dp[i] = max(dp[i], dp[j] + 1)
    ans = dp[-1] + K
    print(ans)

 试题I:最优清零方案 本题总分:25分


【问题描述】
给定一个长度为Ⅳ的数列A1,A2,…… ,Ax。现在小蓝想通过若干次操作将这个数列中每个数字清零。
每次操作小蓝可以选择以下两种之一:1.选择一个大于0的整数,将它减去1;
2.选择连续K个大于0的整数,将它们各减去1。小蓝最少经过几次操作可以将整个数列清零?
【输入格式】
输入第一行包含两个整数N和K。第二行包含Ⅳ个整数A1,A2,…· ,AN e
【输出格式】
输出一个整数表示答案。

n, k = map(int, input().split())
nums = list(map(int, input().split()))
i = 0
ans = 0#操作数
while i < n:
    if i > n - k:
        # 当接近数组末尾时,特别处理
        break
    min_value = min(nums[i:i+k])
    min_idx = nums.index(min_value, i, i+k)

    for x in range(i, min(n, i+k)):
        nums[x] -= min_value
    i = min_idx + 1
    ans += min_value

# 处理数组无法两两删除的元素
for x in range(n):
    ans += nums[x]
print(ans)
  • 13
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值