1.思维题/杂题:数学公式,分析题意,找规律
2.BFS/DFS:广搜(递归实现),深搜(deque实现)
3.简单数论:模,素数(只需要判断到 int(sqrt(n))+1),gcd,lcm,快速幂(位运算移位操作),大数分解(分解为质数的乘积)
4.简单图论:最短路(一对多(Dijstra,临接表,矩阵实现),多对多(Floyd,矩阵实现)),最小生成树(并查集实现)
5.简单字符串处理:最好转为列表操作
6.DP:线性DP,最长公共子序列,0/1背包问题,最长连续字符串,最大递增子串
7.基本算法:二分,贪心,组合,排列,前缀和,差分
8.基本数据结构:队列,集合,字典,字符串,列表,栈,树
9.常用模块:math,datetime,sys中的设置最大递归深度(sys.setrecursionlimit(3000000)),collections.deque(队列),itertools.combinations(list,n)(组合),itertools.permutations(list,n)(排列) heapq(小顶堆)
目录
题型:
刷题:1.《GCD》真题练习(思维 ,数学性质,gcd)
2.《青蛙过河》真题练习(二分,数学思维)
3.《因数平方和》真题练习(数论)
4. 《卡片》真题演习(思维)
5.《直线》真题演习(空间直线,集合)
6.《货物摆放》真题演习(去重,大数分解,因数分解)
7.路径(Floyd算法)
8.《回路计数》真题演习(dp)
9.《时间显示》真题演习(格式化输出)
10.《杨辉三角形》真题演习(二分,难题骗分就行)
11.《左孩子右兄弟》真题演习(dfs,树)
12.《异或数列》真题演习(难,不要这分)
13.《括号序列》真题演习(只要暴力分即可)
14.门牌制作(字符串操作)
15.《 寻找 2020》真题演习(暴力循环字符串操作)
16.《跑步锻炼》真题演习(datetime库的使用)
17.《蛇形填数》真题演习(思维规律)
18.《排序》真题演习(全排列,找规律)
19.《装饰珠》真题演习编辑
20.《 成绩统计》真题演习(选择)
21.《单词分析》真题演习(内置函数,max,min)
22.《 数字三角形》真题演习(暴力循环)
23.《平面切分》真题演习(找规律)
初步思路:暴力枚举k,这样我感觉不能通过全部数据,题目要求找到最小k值。
找规律看看有不有规律?(错误了,只过了2个测试点)
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
import functools # 自定义比较函数 -1不变,1交换
'''
12 23 34 45 56 67 0
13 35 57 79 (2 1)
14 47 25 36 (3 2)
15 59 (4 1)
16 5 10 (5 4)
# 规律,相差为质数,就是质数-1 即d-1
'''
def is_prime(x):
for i in range(2,int(math.sqrt(x))+1):
if x%2==0:
return False
else:
return True
a,b=map(int,input().split())
if is_prime(abs(b-a)):
print(abs(a-b)-1)
else:
print(0)
正解:性质:gcd(a,b)=gcd(a-b,b)
gcd(a+k,b+k)=gcd(a+k,b-a)≤min(a+k,b-a),直接让gcd=b-a,保证gcd最大
标程:
a, b = map(int, input().split())
r = a % (b - a)
if r == 0:
print(0)
else:
print(b - a - r)
初步思路:通过深搜DFS做,一个标记数组,维护石头数,(次数,位置)
正解:答案存在单调性,最小跳跃距离为1,最大为n,通过二分答案进行求解。
标程:
n, x = list(map(int, input().split()))
H = [0, *list(map(int, input().split()))] #下标从1开始
Pre_Sum = [0] * (n)
for idx in range(1, n): #预处理前缀和
Pre_Sum[idx] = Pre_Sum[idx - 1] + H[idx]
#判定能力为y时,是否合法
def check(y):
#枚举所有长度为y的区间
for l in range(1, n - y + 1):
r = l + y - 1
if Pre_Sum[r] - Pre_Sum[l - 1] < 2 * x:
return False
return True
#二分答案
l, r = 1, n
ans = -1
while l <= r:
mid = (l + r) // 2
if check(mid):
ans = mid
r = mid - 1
else:
l = mid + 1
print(ans)
初步思路:暴力循环
正解:考虑优化,记录每个因子出现次数
标程:
MOD = 1000000007
#求数字1-n的平方和
def S(x):
return x * (x + 1) * (2 * x + 1) // 6
n = int(input())
ans = 0
l = 1
#枚举左端点
while l <= n:
r = min(n // (n // l), n)
ans += (n // l) * (S(r) - S(l - 1))
l = r + 1
print(ans % MOD)
初步思路:看谁用的最少,然后循环,用完跳出就行
正解:一样
标程:
a = [2021 for i in range(10)]
def check(x):
while(x > 0):
now = int(x % 10)
if(a[now] > 0):
a[now] -= 1
else:
return 0
x = x // 10
return 1
cnt = 1
while(check(cnt)):
cnt += 1
print(cnt - 1)
初步思路:通过集合去重放不同斜率,垂直于x轴的单独计算数量
正解:一样,但是要注意小数精度问题,利用集合去重
标程:
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
import functools # 自定义比较函数 -1不变,1交换
import os
import sys
# 请在此输入您的代码
m=set()
for i in range(0,20): # 0-1
for j in range(0,21): # 0-2
for x in range(0,20):
for y in range(0,21):
if x-i!=0:
# y=kx+b
k=(y-j)/(x-i)
b=y-k*x
m.add((round(k,5),round(b,5))) # 精度问题,不保留小数会出现问题
#m.add((k,b)) # 除法保留16位小数
print(len(m)+20)
初步思路:无
正解:记录n的因子,3重循环遍历因子组合,有一个优化,就是前两重因子如果相乘大于n了,就跳过进行下一层循环,剪枝操作。
通过大数分解将n质因数分解,然后通过BFS遍历有多少种组合,即
(len(质因数个数),x,y,z),用集合去重。
标程:
n = 2021041820210418
i = 1
a = []
cnt = 0
while i * i <= n:
if n % i == 0:
a.append(i)
if i != n / i:
a.append(int(n / i))
i += 1
for i in range(len(a)):
for j in range(len(a)):
if a[i] * a[j] > n:
continue
for k in range(len(a)):
if a[i] * a[j] * a[k] == n:
cnt += 1
print(cnt)
初步思路:Floyd算法(3重循环),或者警察问路那个算法(2重循环)。
正解:Dijstra算法,最简便为Floyd
标程:
import math
def lcm(a, b):
return int(a * b / math.gcd(a, b))
n = 2021
g = [[0 for i in range(1, n + 2)] for j in range(1, n + 2)]
for i in range(1, n + 1):
for j in range(1, n + 1):
if i == j:
g[i][j] = g[j][i] = 0
elif abs(i - j) <= 21:
g[i][j] = g[j][i] = lcm(i, j)
else:
g[i][j] = 1000000000
for k in range(1, n + 1):
for i in range(1, n + 1):
for j in range(1, n + 1):
if g[i][j] > g[i][k] + g[k][j]:
g[i][j] = g[i][k] + g[k][j]
print(g[1][n])
初步思路:首先建图,通过邻接表建图,然后通过dfs搜索,最终回到原点就计数加1.
正解:通过矩阵构建临接矩阵,状态DP
标程:
# python 跑的相当慢,不过这是道填空题就无所谓了
import math
dp = [[0] * (22) for i in range(2100000)]
g = [[0 for i in range(22)] for i in range(22)]
n = 1 << 21
for i in range(1, 22):
for j in range(1, 22):
if math.gcd(i, j) == 1:
g[i - 1][j - 1] = g[j - 1][i - 1] = 1
dp[1][0] = 1
i = 1
while i < n:
for j in range(0, 21):
if (i >> j & 1) == 0:
continue
for k in range(0, 21):
if g[j][k] == 0 or (i >> k & 1) != 0:
continue
dp[(i + (1 << k))][k] += dp[i][j]
i += 1
res = 0
for i in range(0, 21):
res += dp[n - 1][i]
print(res)
初步思路:直接取余计算当天的时分秒,然后进行整除得到时分秒
import os
import sys
# 请在此输入您的代码
n=int(input())
time=n%(1000*60*60*24)
h=time//(1000*60*60)
m=(time-h*1000*3600)//(1000*60)
s=(time-h*1000*3600-m*60*1000)//1000
print('{:0>2d}:{:0>2d}:{:0>2d}'.format(h,m,s))
正解:只考虑最后一天,1s=1000ms
标程:
import os
import sys
n = int(input())
n /= 1000
n %= 24 * 60 * 60
h = int(n / 3600)
m = int(n / 60) % 60
s = int(n % 60)
if h <= 9:
h = str(0) + str(h)
else :
h = str(h)
if m <= 9:
m = str(0) + str(m)
else:
m = str(m)
if s <= 9:
s = str(0) + str(s)
else:
s = str(s)
print(h + ':'+ m + ':' + s)
初步思路:先把前面几十行的数值计算出来,拼接成一行,通过列表的索引来求值
正解:二分行号
import os
import sys
# 请在此输入您的代码
n=[0,1,1,1,1,2,1]
#n=[[0],[1,1],[1,2,1]]
last=[1,2,1]
for i in range(50):
new=[]
for a,b in zip(last+[0],[0]+last):
new.append(a+b)
n.append(new)
last=new
m=int(input())
print(n.index(m))
正解:
标程:
import os
import sys
n = int(input())
def C(a, b):
res = 1
i = a
j = 1
while j <= b:
res = int(res * i / j)
if res > n:
return int(res)
i -= 1
j += 1
return int(res)
for k in range(16, -1, -1):
l = 2 * k
r = max(n, l)
res = int(-1)
while l <= r:
mid = l + r >> 1
if C(mid, k) >= n:
res = mid
r = mid - 1
else:
l = mid + 1
if C(res, k) == n:
print((res + 1) * res // 2 + k + 1)
break
初步思路: 无
正解:通过列表存储多叉树,dfs搜索,即dfs(i) i根二叉树最高高度
dfs(i)=孩子的数目 + max()dfs(各孩子))
5
1 1 [ 2 3 4 ]
1 2 [ 5 ]
1 3 [ ]
2 4 [ ]
5 [ ]
标程:
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
import functools # 自定义比较函数 -1不变,1交换
n = int(input())
A = [[]for i in range(n+1)]
for i in range(2,n+1):
v=int(input())
A[v].append(i) # 添加子节点
def dfs(i):
if A[i] is None:
return 0
maxn = 0
for j in A[i]:
maxn = max(maxn ,dfs(j))
return len(A[i])+maxn
print(dfs(1))
初步思路:无
正解:博弈论知识
初步思路: 将括号转为0,1数字,看有多少种插入方法,dfs从左到右搜索?
"""
0001
010101
010011
001101
001011
000111"""
标程(暴力):
for(int i = 1 ; i <= cnt ; i ++) dp[1][i] = 1;
if(sum[1] > 0) dp[1][0] = 1;
for(int i = 2 ; i <= n ; i ++){
for(int j = i - sum[i] ; j <= cnt ; j ++){
for(int k = 0 ; k <= j ; k ++){
dp[i][j] += dp[i - 1][k];
dp[i][j] %= mod;
}
}
}
字符串操作
暴力循环就行,统计。
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
import functools # 自定义比较函数 -1不变,1交换
import os
import sys
# 请在此输入您的代码
a="""
022220000002200200202022000202222022202222222202022002222200022200222220020200222020002022222220022202000002220020220002022222022022002022202222222000022002020002202002022000022000202200000220200022200020220222000022202222000222222022202022222022200002202220222000202000200002220200000200202002202202
"""
b=[]
a=a.split() # 300*300
for i in a:
b.append(list(i))
ans=0
#s="002000000220202000222000202200222220202202020002220002020022202200220220202002002220020200000000220022200202222022220222000022220220020020222020022220022220220000022022002020220002200220020020022200020222020200200000020220020022002202000202222020220020020022020000202022220222200022220000000020020020"
#print(len(s))
def check1(i,j):
if i+3<=299 and b[i][j]=='2' and b[i+1][j]=='0' and b[i+2][j]=='2' and b[i+3][j] =='0':
return True
else :
return False
def check2(i,j):
if j+3<=299 and b[i][j]=='2' and b[i][j+1]=='0' and b[i][j+2]=='2' and b[i][j+3] =='0':
return True
else :
return False
def check3(i,j):
if i+3<=299 and j+3<=299 and b[i][j]=='2' and b[i+1][j+1]=='0' and b[i+2][j+2]=='2' and b[i+3][j+3] =='0':
return True
else :
return False
for i in range(300):
for j in range(300):
if check1(i,j):
ans+=1
if check2(i,j):
ans+=1
if check3(i,j):
ans+=1
print(ans)
标程:
n = 300
ans = 0
s = []
for i in range(n):
t = input()
s.append(t)
for i in range(len(s)):
for j in range(len(s[i])):
if j + 3 < len(s[i]) and s[i][j] + s[i][j + 1] + s[i][j + 2] + s[i][j + 3] == '2020':
ans += 1
for i in range(len(s)):
for j in range(len(s[i])):
if i + 3 < len(s) and s[i][j] + s[i + 1][j] + s[i + 2][j] + s[i + 3][j] == '2020':
ans += 1
for i in range(len(s)):
for j in range(len(s[i])):
if i + 3 < len(s) and j + 3 < len(s[i]) and s[i][j] + s[i + 1][j + 1] + s[i + 2][j + 2] + s[i + 3][j + 3] == '2020':
ans += 1
print(ans)
送分题?使用datetime库循环遍历即可
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
import functools # 自定义比较函数 -1不变,1交换
import datetime # date,timedelta,isoweekday()
begin=datetime.date(2000,1,1)
end=datetime.date(2020,10,1)
delta=datetime.timedelta(1)
ans=0
while begin !=end:
if begin.day==1 or begin.isoweekday()==1: #月初或者星期一
ans+=2
else: ans+=1
begin+=delta
print(ans+2)
标程:
import os
import sys
import datetime
start = datetime.date(2000, 1, 1)
end = datetime.date(2020, 10, 1)
days = datetime.timedelta(days=1)
ans = 0
while end >= start:
if start.day == 1 or start.weekday() == 0:
ans += 2
else:
ans += 1
start += days
print(ans)
找规律的题
初步思路:题意都读不懂,跳了
选择判断,送分题
import os
import sys
n = int(input())
cnt1 = 0
cnt2 = 0
for i in range(1 , n + 1):
x = int(input())
if x >= 60:
cnt1 +=1
if x >= 85:
cnt2 += 1
print("{:.0f}%".format(round(100.0 * cnt1 / n , 2)))
print("{:.0f}%".format(round(100.0 * cnt2 / n , 2)))
送分,使用内置函数寻找最大最小
import os
import sys
s = input()
ma = 0
ch = 'z'
for j in s:
cnt = s.count(j)
if cnt >= ma:
ma = cnt
for j in s:
if s.count(j) == ma:
ch = min(ch , j)
print(ch)
print(ma)
初步思路:从上到下遍历,因为向左下走的次数与向右下走的次数相差不能超过 1,最后的终点肯定是中间位置。
import os
import sys
dp = []
n = int(input())
for i in range(n):
dp.append(list(map(int, input().split())))
for i in range(n):
for j in range(i + 1):
if i == 0:
dp[i][j] = dp[i][j]
elif j == 0:
dp[i][j] = dp[i - 1][j] + dp[i][j]
elif j == i:
dp[i][j] = dp[i - 1][j - 1] + dp[i][j]
else:
dp[i][j] = max(dp[i - 1][j - 1],dp[i - 1][j]) + dp[i][j]
if n % 2 == 0:
print(max(dp[n - 1][n // 2 - 1],dp[n - 1][n // 2]))
else:
print(dp[n - 1][n // 2])
初步思路:画图找规律
正解:增加n个交点,就增加n+1个平面,注意去重,交点和线去重。
标程:
import os
import sys
n = int(input())
line = set()
node = set()
ans = 1
def calc(a , b):
node.clear()
for j in line:
A = j[0]
B = j[1]
if A == a:
continue
x = 1.0 * (B - b) / (a - A)
y = x * a + b
node.add((x , y));
return len(node) + 1
for i in range(n):
a, b = list(map(int, input().split()))
if (a, b) in line:
continue
ans += calc(a , b)
line.add((a, b))
print(ans)