A美丽的2
答案:563
res = 0
for i in range(1, 2021):
if '2' in str(i):
res += 1
print(res)
# 563
B合数个数
模拟即可
答案:1713
def check(n):
for i in range(2, n):
if n % i == 0:
return True
return False
res = 0
for i in range(1, 2021):
if check(i):
res += 1
print(res)
# 1713
C阶乘约数
思路:需要一点数学知识
任意一个正整数n都可以表示成若干个素数的乘积: n = p 1 a 1 ∗ p 2 a 2 ∗ . . . ∗ p k a k n=p_{1} ^{a_{1}}*p_{2} ^{a_{2}}*...*p_{k} ^{a_{k}} n=p1a1∗p2a2∗...∗pkak
约 数 个 数 = ( a 1 + 1 ) ∗ ( a 2 + 1 ) ∗ . . . ∗ ( a k + 1 ) 约数个数=(a_{1}+1)*(a_{2}+1)*...*(a_{k}+1) 约数个数=(a1+1)∗(a2+1)∗...∗(ak+1)
答案:39001250856960000
from math import *
def isPrime(n):
for i in range(2, floor(sqrt(n))+1):
if n % i == 0:
return False
return True
fac = {}
n = 100
for i in range(2, n+1):
tmp = i
num = 2
while tmp > 1:
while tmp % num == 0:
fac[num] = fac.get(num, 0) + 1
tmp //= num
num += 1
while not isPrime(num):
num += 1
res = 1
for key, value in list(fac.items()):
res *= value+1
print(res)
# 39001250856960000
D本质上升序列
思路:动态规划,和经典的最长不下降子序列类似,构造dp数组表示以第i个字符结尾的子序列的个数,对于字符串中每一个字符,遍历其前面的所有字符,若是当前字符比前面的大,满足递增要求,加上前面的数量;若是小于,不用理会;若是等于,由于当前的比前面的长,所以当前的包含了前面的,要减去前面的重复部分的数量。
答案:3616159
s = "tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl"
dp = [1]*len(s) # dp[i]表示以第i个字符结尾的子序列的个数
for i in range(1, len(s)):
for j in range(i):
if s[i] > s[j]:
dp[i] += dp[j]
if s[i] == s[j]:
dp[i] -= dp[j] # 减去和前面重复的部分
print(sum(dp))
# 3616159
E玩具蛇
思路:深搜,没固定起点,所以每一个方格都作为起点搜一遍,注意下一次搜的时候把前一次的起点的状态还原。
答案:552
def dfs(x, y, current):
global res
if current > 16:
res += 1
return
for i in range(4):
tx, ty = x+dx[i], y+dy[i]
if 0 <= tx < 4 and 0 <= ty < 4 and graph[tx][ty] == 0:
graph[tx][ty] = current
dfs(tx, ty, current+1)
graph[tx][ty] = 0
res = 0
graph = [[0]*4 for _ in range(4)]
dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]
for i in range(4):
for j in range(4):
graph[i][j] = 1
dfs(i, j, 2)
graph[i][j] = 0
print(res)
# 552
F天干地支
【问题描述】
古代中国使用天干地支来记录当前的年份。
天干一共有十个,分别为:甲(jiǎ)、乙(yǐ)、丙(bǐng)、丁(dīng)、戊
(wù)、己(jǐ)、庚(gēng)、辛(xīn)、壬(rén)、癸(guǐ)。
地支一共有十二个,分别为:子(zǐ)、丑(chǒu)、寅(yín)、卯(mǎo)、辰(chén)、巳(sì)、午(wǔ)、未(wèi)、申(shēn)、酉(yǒu)、戌(xū)、亥(hài)。
将天干和地支连起来,就组成了一个天干地支的年份,例如:甲子。2020 年是庚子年。
每过一年,天干和地支都会移动到下一个。例如 2021 年是辛丑年。
每过 60 年,天干会循环 6 轮,地支会循环 5 轮,所以天干地支纪年每 60年轮回一次。例如 1900 年,1960 年,2020 年都是庚子年。
给定一个公元纪年的年份,请输出这一年的天干地支年份。
【输入格式】
输入一行包含一个正整数,表示公元年份。
【输出格式】
输出一个拼音,表示天干地支的年份,天干和地支都用小写拼音表示(不表示声调),之间不要加入任何多余的字符。
【样例输入】
2020
【样例输出】
gengzi
【评测用例规模与约定】
对于所有评测用例,输入的公元年份为不超过 9999 的正整数。
思路:
有个关于天干地支的计算方法:
(年份- 3)%10对天干:如1894-3=1891 ,1891除以10余数是1即为甲;
(年份- 3)%12对地支:如1894-3=1891 ,1891除以12余数是7即为午,即1894年是甲午年。
注意:如果下标从0开始就得减4
不过一般人不知道这个计算方法,那该怎么算呢?题目中说2020年是庚子年,将2020模一下60得到40,所以公元40年也是庚子年,把这个作为切入点按照规律走一遍就能得到一张模完60之后的映射表,代码如下:
year = int(input())
tiangan = ['jia', 'yi', 'bing', 'ding',
'wu', 'ji', 'geng', 'xin', 'ren', 'gui']
dizhi = ['zi', 'chou', 'yin', 'mao', 'chen',
'si', 'wu', 'wei', 'shen', 'you', 'xu', 'hai']
table = ['']*60
table[40] = tiangan[6]+dizhi[0] # 公元40年是庚子年,依据这个建表,并且庚和子的下标分别是6和0
i, j = 7, 1
cnt = 41
while cnt != 40:
table[cnt] = tiangan[i]+dizhi[j]
i = (i+1) % 10
j = (j+1) % 12
cnt = (cnt+1) % 60
print(table[year % 60])
# 100%
G重复字符串
【问题描述】
如果一个字符串 S 恰好可以由某个字符串重复 K 次得到,我们就称 S 是 K 次重复字串。例如 “abcabcabc” 可以看作是 “abc” 重复 3 次得到,所以“abcabcabc” 是 3 次重复字符串。
同理 “aaaaaa” 既是 2 次重复字符串、又是 3 次重复字符串和 6 次重复字符串。
现在给定一个字符串 S,请你计算最少要修改其中几个字符,可以使 S 变为一个 K 次字符串?
【输入格式】
输入第一行包含一个整数 K。
第二行包含一个只含小写字母的字符串 S。
【输出格式】
输出一个整数代表答案。如果 S 无法修改成 K 次重复字符串,输出 1。
【样例输入】
2
aabbaa
【样例输出】
2
【评测用例规模与约定】
对于所有评测用例,1 ≤ K ≤ 100000, 1 ≤ |S | ≤ 100000。其中 |S | 表示 S 的
长度。
思路:将字符串分割成k段,假设每段m个字符,我们统计每段相同位置的每种字符出现的次数,每段都统计上后,每个位置(0 ~ m-1)都取出现次数最多的字符作为要变成的字符,将每一段的对应位置的字符都变成这个字符就行了,因为这个字符在该位置出现最多,其他字符变到该字符能保证次数最少,如果要是变成别的字符,那么出现次数最多的字符变动次数会很多,并非最优解。累加每个位置(0 ~ m-1)上变换次数就是答案。
k = int(input())
s = input()
if k > len(s):
print(-1)
else:
res = 0
length = len(s)//k
for i in range(length):
dic = {}
for j in range(k):
word = s[j*length+i]
dic[word] = dic.get(word, 0)+1
d = list(dic.items())
d.sort(key=lambda x: x[1], reverse=True)
res += k-d[0][1]
print(res)
# 100%
H答疑
【问题描述】
有 n 位同学同时找老师答疑。每位同学都预先估计了自己答疑的时间。
老师可以安排答疑的顺序,同学们要依次进入老师办公室答疑。
一位同学答疑的过程如下:
首先进入办公室,编号为 i 的同学需要 si 毫秒的时间。
然后同学问问题老师解答,编号为 i 的同学需要 ai 毫秒的时间。
答疑完成后,同学很高兴,会在课程群里面发一条消息,需要的时间可以忽略。
最后同学收拾东西离开办公室,需要 ei 毫秒的时间。一般需要 10 秒、
20 秒或 30 秒,即 ei 取值为 10000,20000 或 30000。
一位同学离开办公室后,紧接着下一位同学就可以进入办公室了。
答疑从 0 时刻开始。老师想合理的安排答疑的顺序,使得同学们在课程群
里面发消息的时刻之和最小
【输入格式】
输入第一行包含一个整数 n,表示同学的数量。
接下来 n 行,描述每位同学的时间。其中第 i 行包含三个整数 si, ai, ei,意
义如上所述。
【输出格式】
输出一个整数,表示同学们在课程群里面发消息的时刻之和最小是多少。
【样例输入】
3
10000 10000 10000
20000 50000 20000
30000 20000 30000
【样例输出】
280000
【样例说明】
按照 1, 3, 2 的顺序答疑,发消息的时间分别是 20000, 80000, 180000。
【评测用例规模与约定】
对于 30% 的评测用例,1 ≤ n ≤ 20。
对于 60% 的评测用例,1 ≤ n ≤ 200。
对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ si ≤ 60000,1 ≤ ai ≤ 1000000, ei ∈ {10000, 20000, 30000},即 ei 一定是 10000、20000、30000 之一。
思路:利用贪心的思想简单排序一下即可
若a在b前面,则a需要的时间为a的si+a的ei,b需要的时间为sum(a)+b的si+b的ei
若b在a前面,同理,两者比较一下即可。虽然做差的时候有几项是会约掉的,等效于sum(a)和sum(b)比较,但是写进去更便于理解。
代码如下:
from functools import cmp_to_key
def cmp(a, b):
ta = a[0]+a[1]+sum(a)+b[0]+b[1] # a在b前面,两人用的总时间
tb = b[0]+b[1]+sum(b)+a[0]+a[1] # b在a前面,两人用的总时间
return ta-tb
n = int(input())
time = []
for _ in range(n):
time.append(list(map(int, input().split())))
time.sort(key=cmp_to_key(cmp))
res = 0
clock = 0
for s, a, e in time:
clock += s+a
res += clock
clock += e
print(res)
# 100%
I补给
【问题描述】
小蓝是一个直升飞机驾驶员,他负责给山区的 n 个村庄运送物资。每个月,他都要到每个村庄至少一次,可以多于一次,将村庄需要的物资运送过去。每个村庄都正好有一个直升机场,每两个村庄之间的路程都正好是村庄之间的直线距离。
由于直升机的油箱大小有限,小蓝单次飞行的距离不能超过 D。每个直升机场都有加油站,可以给直升机加满油。每个月,小蓝都是从总部出发,给各个村庄运送完物资后回到总部。如果方便,小蓝中途也可以经过总部来加油。
总部位于编号为 1 的村庄。请问,要完成一个月的任务,小蓝至少要飞行多长距离?
【输入格式】
输入的第一行包含两个整数n, D,分别表示村庄的数量和单次飞行的距离。
接下来n行描述村庄的位置,其中第i行两个整数
x
i
,
y
i
x_{i},y_{i}
xi,yi,表示编号为i的
村庄的坐标。村庄i和村庄j之间的距离为
(
x
i
−
x
j
)
2
+
(
y
i
−
y
j
)
2
\sqrt{(x_{i}-x_{j})^{2}+(y_{i}-y_{j})^{2}}
(xi−xj)2+(yi−yj)2。
【输出格式】
输出一行,包含一个实数,四舍五入保留正好 2 位小数,表示答案。
【样例输入】
4 10
1 1
5 5
1 5
5 1
【样例输出】
16.00
【样例说明】
四个村庄形成一个正方形的形状。
【样例输入】
4 6
1 1
4 5
8 5
11 1
【样例输出】
28.00
【样例说明】
补给顺序为 1 → 2 → 3 → 4 → 3 → 2 → 1。
【评测用例规模与约定】
对于所有评测用例,1 ≤ n ≤ 20, 1 ≤ xi, yi ≤ 104, 1 ≤ D ≤ 105。
思路:Floyd+状压dp
蓝桥杯练习系统里,python版本只能过80%(超时),c++相同思路能全过
from math import *
def getDistance(x, y):
return sqrt(pow(location[x][0]-location[y][0], 2)+pow(location[x][1]-location[y][1], 2))
n, d = map(int, input().split())
location = [tuple(map(int, input().split())) for _ in range(n)]
w = [[float('inf')]*n for _ in range(n)] # w[i][j]表示i号村庄和j号村庄之间的最短距离
# 建立邻接矩阵
for i in range(n):
for j in range(n):
dis = getDistance(i, j)
if dis <= d:
w[i][j] = dis
# Floyd算法
for k in range(n):
for i in range(n):
for j in range(n):
w[i][j] = min(w[i][j], w[i][k]+w[k][j])
# dp[i][j]表示在状态i下,从0号村庄到j号村庄的最短录
dp = [[float('inf')]*n for _ in range(1 << n)]
dp[1][0] = 0
for i in range(1, 1 << n): # 枚举状态
for j in range(n): # 枚举村庄
if i >> j & 1 == 1: # 如果j号村庄状态为1
for k in range(n):
if (i-(1 << j)) >> k & 1: # 如果除了j号剩下的村庄中状态为1
dp[i][j] = min(dp[i][j], dp[i - (1 << j)][k]+w[k][j])
res = float('inf')
for i in range(n): # 枚举最后从哪个村庄返回起点,也就是最后一个访问的村庄
res = min(res, dp[(1 << n)-1][i]+w[i][0])
print('{:.2f}'.format(res))
# 80%
J蓝跳跳
【问题描述】
小蓝制作了一个机器人,取名为蓝跳跳,因为这个机器人走路的时候基本
靠跳跃。
蓝跳跳可以跳着走,也可以掉头。蓝跳跳每步跳的距离都必须是整数,每步可以跳不超过 k 的长度。由于蓝跳跳的平衡性设计得不太好,如果连续两次
都是跳跃,而且两次跳跃的距离都至少是 p,则蓝跳跳会摔倒,这是小蓝不愿意看到的。
小蓝接到一个特别的任务,要在一个长为 L 舞台上展示蓝跳跳。小蓝要控制蓝跳跳从舞台的左边走到右边,然后掉头,然后从右边走到左边,然后掉头,然后再从左边走到右边,然后掉头,再从右边走到左边,然后掉头,如此往复。为了让观者不至于太无趣,小蓝决定让蓝跳跳每次用不同的方式来走。小蓝将蓝跳跳每一步跳的距离记录下来,按顺序排成一列,显然这一列数每个都不超过 k 且和是 L。这样走一趟就会出来一列数。如果两列数的长度不同,或者两列数中存在一个位置数值不同,就认为是不同的方案。
请问蓝跳跳在不摔倒的前提下,有多少种不同的方案从舞台一边走到另一边。
【输入格式】
输入一行包含三个整数 k, p, L。
【输出格式】
输出一个整数,表示答案。答案可能很大,请输出答案除以 20201114 的余数。
【样例输入】
3 2 5
【样例输出】
9
【样例说明】
蓝跳跳有以下 9 种跳法:
1+1+1+1+1
1+1+1+2
1+1+2+1
1+2+1+1
2+1+1+1
2+1+2
1+1+3
1+3+1
3+1+1
【样例输入】
5 3 10
【样例输出】
397
【评测用例规模与约定】
对于 30% 的评测用例,1 ≤ p ≤ k ≤ 50,1 ≤ L ≤ 1000。
对于 60% 的评测用例,1 ≤ p ≤ k ≤ 50,1 ≤ L ≤ 109。
对于 80% 的评测用例,1 ≤ p ≤ k ≤ 200,1 ≤ L ≤ 1018。
对于所有评测用例,1 ≤ p ≤ k ≤ 1000,1 ≤ L ≤ 1018。