试题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)