试题A:
# 签到题,不过不知道是不是的
print("ABC")
试题B:
思路:本题看起来不像有特殊解法的样子...所以一般有两个思路。
一、先找三角数,再判断它是不是回文数。
二、先找回文数,再判断他是不是三角数。
可知我们找到的回文数,不一定能直接就有对应的整数三角数来对应,即可能 n!= k*(k+1)/2 k为整数。而且回文数的查找要么是一个数一个数的递增。要么是直接的构造 ijkji 或ijkkji 这样子输出。不过我们不能一开始就知道答案的位数,写个生成指定位数回文数的函数又比较麻烦,所以我们就选用第二种方式。
首先题目要求找第一个大于20220514的三角回文数。 k^2/2 < n=k*(k+1)/2<(k+1)^2/2所以我们利用计算器给20220514*2开根号,上取整,即得到k+1 的值。
得到k+1 为 6360。 所以我们直接从 k = 6360 开始不断累加判断其是否是回文数,是就返回他的值。
代码
k = 6360
while True:
i = k * (k + 1) // 2
k += 1
s = str(i)
if s[:len(s) // 2] == s[-1:len(s) // 2 - 1:-1]: # 判断是否是回文数部分
print(s)
break
试题C:
思路:
假设卡片数为k,那么任选两张卡片的情况就会有 k*k 种。假设又n个人。
那么 (k-1)^2 < n <= k^2。现在已知人数为n。求k。
代码:
n = int(input())
x = int(n**0.5) # 直接开方,int下取整
if x**2 == n: # 如果n开方就直接为整数,那么答案就直接为x
print(x)
else:
print(x+1) # 否则,答案就为x+1
试题D:
分析:
仔细一看发现就是要按从小到大的顺序输出到岗员工的编号。
代码:
n = int(input())
l = []
for _ in range(n):
l.append(input().split()[1])
l = list(set(l)) # 去重。或者就是直接sort,然后判断于前面的值是不是相同,不同就输出。
l.sort()
for i in range(len(l)):
print(l[i])
试题E:
分析:
分析不出来
代码:
试题F:
分析:
我想的是套用bfs的模板,使时间的复杂度有些高的。但是基本的案例还是能过的。
代码:
n, m = map(int, input().split())
Map = [] ## 时间图
Detect = [[0 for i in range(m)] for j in range(n)]
Detect[0][0] = 1
for _ in range(n):
Map.append(list(map(int, input().split())))
duilie = [[Map[0][0], 0, 0]] # 每个都记为数值,行列。
direction = [[0, 1], [1, 0], [0, -1], [-1, 0]] # 方向
num = 0 # 染色完的个数
t = 0 # 所花费的时间
while num < n * m:
t_min = min(duilie)[0]
t += t_min
N_dui = []
for i in duilie:
i[0] -= t_min
if i[0] == 0:
i[0] = 0xffffffff # 普通队列,我就直接把变为零的值直接搞到最大,相当于去除
# 缺点就是重复计算的次数多,时间复杂度大
# 可以换为优先队列,变为0后就直接弹出,
num += 1
for j in range(4): # 经典四个方向探测
x, y = [i[1] + direction[j][0], i[2] + direction[j][1]]
if x not in range(n) or y not in range(m) or Detect[x][y] == 1:
continue
else:
Detect[x][y] = 1
N_dui.append([Map[x][y], x, y])
duilie = duilie + N_dui # 新探测出来的点的队列加到之前的队列上
print(t)
之后再写一个优先队列的。
试题G:
分析:
一开始看到这个题的时候感觉有点奇怪,哎呀遍历就完了。hhh
代码:
n, k = map(int, input().split())
nums = list(map(int, input().split()))
ans = 0
for i in range(n):
res = 0
for j in range(i, n):
res += nums[j]
if res // k >= 0 and res % k == 0:
ans += 1
print(ans)
时间复杂度应该和用前缀和差不多,所以就没必要了。这个思路还是很巧妙的我感觉。
试题H:
思路:
首先是要找素数吧,写个素数筛的代码。
代码:
试题I:
思路:
直接就按题目写,想不到高级的方法了。
代码:
n = int(input())
nums = list(map(int, input().split()))
m = int(input())
query = []
for _ in range(m):
query.append(list(map(int, input().split())))
def change(L):
nums[L[1] - 1] = L[2]
def compare(L):
n = 1
for i in range(L[1] - 1, L[2]):
if nums[i] < nums[L[3] - 1]:
n += 1
print(n, end=' ')
for i in query:
if i[0] == 1:
change(i)
elif i[0] == 2:
compare(i)
不清楚能不能过所有的测试点。
试题J:
分析:
我们首先考虑单峰序列,一个长度为n的序列最多又多少种排列的情况?答案是2^(n-1)种。就是这样子,差不多了。
再考虑一个长度为n,和为m的数列有多少种情况。这个就用递归。
然后题目一下就说啥最后的数太大啥的,所以就来个快速幂加上
代码:
n, m = map(int, input().split())
def fi(m, i, k=0): # 找和为m,长度为i 的单增序列的可能数。k是前一个数的值
n = 0 # n就为结果
if m <= k: # 当后面数的总数小于等于前面一个数时,就已经寄了 返回0
return 0
elif i == 1: # 没有寄,还到了i等于1 的位置就返回 1
return 1
for x in range(k + 1, m // i + 1): # 遍历的位置从大于上一个,到i个平均这m 的数
n += fi(m - x, i - 1, x)
return n
def ksm(a, b, c): # 快速幂自己看吧...
if b == 1:
return a
if b % 2 == 0:
return ksm(a * a % c, b // 2, c)
elif b % 2 != 0:
return ksm(a * a % c, b // 2, c) * a
ans = 0
for i in range(2, n + 1): # 长度从2遍历到n
step = ksm(2, i - 1, 1000000007) # 长度为i的时候的排序数量 模上 要求的数
ans += fi(m, i) * step
ans %= 1000000007
print((ans + 1) % 1000000007) # 加上长度为1的一种情况
结尾
暂时先这样吧,有时间再补一下,前面两题和省赛第一场。