目录
bisect
# 179 日志统计
import bisect
n, d, k = map(int, input().split())
m = [[] for _ in range(int(10e5+50))]
post = set()
for i in range(n):
ts, id = map(int, input().split())
post.add(id)
m[id].append(ts)
post = sorted(post)
for id in post:
m[id] = sorted(m[id])
for i in range(len(m[id])):
td = m[id][i] + d
if bisect.bisect_left(m[id], td) - i >= k:
print(id)
break
functools.cmp_to_key
import functools
def cmp(n1, n2):
if n1[1] != n2[1]:
return -1 if n1[1] > n2[1] else 1 # -1升序1降序
elif n1[2] != n2[2]:
return -1 if n1[2] > n2[2] else 1
else:
return 1 if n1[0] > n2[0] else -1
n = int(input())
scores = []
for i in range(n):
score = list(map(int, input().split()))
scores.append([i+1, sum(score)] + score)
scores = sorted(scores, key=functools.cmp_to_key(cmp))
for i in range(5):
print(scores[i][0], scores[i][1])
gcd和lcm
# gcd: greatest common divisor 最大公约数
# lcm: Least Common Multiple 最小公倍数
def gcd(a, b):
while b:
a, b = b, a % b
return a
print(gcd(12, 15))
# a = 15 b = 12
# a = 12 b = 3
# a = 3 b = 0
# return 3
def lcm(a, b):
s = a * b
return s // gcd(a, b)
print(lcm(12, 15))
# 12 * 15 / 3
二分
ls = list(i ** 2 for i in range(1, 11))
print(ls)
def binary_search(n): # 二分查找基础概念算法
low = 0
high = len(ls)
while low < high:
mid = (low + high) // 2
if mid == n:
return ls[mid]
elif n < mid:
high = mid - 1
else:
low = mid + 1
n = int(input())
res = binary_search(n)
print(res)
# 二分题目模板
# check函数是核心
def check(x):
pass
# 假设x为答案
# 题目一般有有个约束条件
# 如果通过某种手段使得在x的条件下存在符合约束条件的解
# 那么就是可行解
# 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用,把中间点放在左半边,不管三七二十一先用这个,做题过程中再修改
def bsearch_1(l, r):
while l < r:
mid = l + r >> 1 # 取中间值
if check(mid): # 判断是否满足某种性质
r = mid # 更新区间
else:
l = mid + 1
return l
# 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用,把中间点放在左半边(比如左边是合法的,右边是不合法的,此时mid属于合法的那一边)
def bsearch_2(l, r):
while l < r:
mid = l + r + 1 >> 1 # 取中间值
if check(mid): # 判断是否满足某种性质
l = mid # 更新区间
else:
r = mid - 1
return l
倍增法(ST)
# 1205区间最大值
from math import *
N = 100001
dp = [[0] * 40 for i in range(N)]
n, m = map(int, input().split())
a = [0] + list(map(int, input().split()))
def st_init():
global dp
for i in range(1, n + 1):
dp[i][0] = a[i] # dp[s][k]表示左端点是s,区间长度为2**k的区间最值
p = int(log2(n))
for k in range(1, p + 1):
for s in range(1, n + 2 - (1 << k)): # 1<<(k-1) 表示2的k-1次方
dp[s][k] = max(dp[s][k - 1], dp[s + (1 << (k - 1))][k - 1])
def st_query(L, R):
k = int(log2(R - L + 1))
return max(dp[L][k], dp[R - (1 << k) + 1][k])
st_init()
for i in range(1, m + 1):
L, R = map(int, input().split())
print(st_query(L, R))
前缀和,差分
# # 前缀和模板(一维)
# a = [0] + list(map(int, input().split()))
# s = [0] * len(a)
# for i in range(1, len(a)+1):
# s[i] = s[i - 1] + a[i]
# print(a, s, sep='\n')
# left, right = map(int, input().split())
# print(s[right] - s[left]) # a[left+1]到a[right]间所有数的和
# print("------------------")
# # 前缀和模板(二维)
# # S[i][j] = a[i][j] + S[i-1][j] + S[i][j-1] - S[i-1][j-1]
# # ----S[i-1][j-1]为S[i-1][j]和S[i][j-1]重叠部分,多加了一次,故减掉
# n, m = map(int, input().split()) # n行m列
# a = [[0] * (m+1)] + [[0] + list(map(int, input().split())) for i in range(n)]
# s = [[0] * (m+1) for i in range(n+1)]
# for i in range(1, n+1):
# for j in range(1, m+1):
# s[i][j] = a[i][j] + s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]
# print(a, s, sep='\n')
# left_x, left_y, right_x, right_y = map(int, input().split())
# print(s[right_x][right_y] - s[left_x][left_y])
# 差分模板(一维)
a = [0, 1, 2, 3, 4]
b = [0] * 5
for i in range(1, len(a)):
b[i] = b[i - 1] + a[i]
print(a, b, sep='\n') # a是b的差分数组,b是a的前缀和数组
print("----------------")
# 构建差分数组
c = [0, 1, 2, 3, 4]
print(c)
d = c[:]
e = c[:]
for i in range(1, len(d)):
d[i] = d[i] + d[i - 1]
print(d)
l, r = 1, 3
e[l] += 1
e[r + 1] -= 1
for i in range(1, len(e)):
e[i] += e[i - 1]
print(e)
# 例题真题14: 重新排序(前缀和,差分)
# 真题15: k倍区间(前缀和)
# 矩阵前缀和案例 2109 统计子矩阵
n, m, k = map(int, input().split())
a = [[0] for i in range(n)]
a.insert(0, [0] * (m + 1))
for i in range(1, n + 1):
a[i].extend(map(int, input().split()))
s = [[0] * (m + 1) for i in range(n + 1)]
for i in range(1, n + 1):
for j in range(1, m + 1):
s[i][j] = a[i][j] + s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]
ans = 0
for i1 in range(1, n + 1):
for i2 in range(i1, n + 1):
for j1 in range(1, m + 1):
for j2 in range(j1, m + 1):
z = s[i2][j2] - s[i1 - 1][j2] - s[i2][j1 - 1] + s[i1 - 1][j1 - 1]
if z <= k:
ans += 1
print(ans)
# 2109 双指针优化版
n, m, k = map(int, input().split())
a = [[0] for i in range(n)]
a.insert(0, [0] * (m+1))
for i in range(1, n+1):
a[i].extend(map(int, input().split()))
s = [[0] * (m+1) for i in range(n+1)]
for i in range(1, n+1):
for j in range(1, m+1):
s[i][j] = s[i-1][j] + a[i][j]
ans = 0
for i1 in range(1, n+1):
for i2 in range(i1, n+1):
j1 = 1
z = 0
for j2 in range(1, m+1):
z += s[i2][j2] - s[i1-1][j2]
while z > k:
z -= s[i2][j1] - s[i1-1][j1]
j1 += 1
ans += j2 - j1 + 1
print(ans)
区间合并
def merge(intervals: list):
if len(intervals) == 0:
return intervals
intervals.sort(key=lambda x: x[0])
result = [intervals[0]]
for i in range(1, len(intervals)):
last = result[-1]
if last[1] >= intervals[i][0]: # 重叠
result[-1] = [last[0], max(last[1], intervals[i][1])]
else:
result.append(intervals[i])
print(result)
n = 4
# intervals = [[1, 3], [2, 6], [8, 10], [15, 18]]
intervals = [[1, 5], [3, 8], [9, 14], [14, 20]]
merge(intervals)
双指针(尺取法)
# 1372 美丽的区间
n, s = map(int, input().split())
a = list(map(int, input().split()))
cnt = 0
ans = 10e8
i, j = 0, 0
while i < len(a):
if cnt < s:
cnt += a[i]
i += 1
else:
ans = min(ans, i-j)
cnt -= a[j]
j += 1
if ans == 10e8:
print(0)
else:
print(ans)
唯一分解定理和质因数分解
# 唯一分解定理:又称为正整数的唯一分解定理,即:每个大于1的自然数均可写为质数的积
# n > 1, n = (2^a)(3^b)(5^c)(7^d)...(x^y) x为质数
# 因为2的倍数已经涵盖了所有偶数,所以x只会是质数
# 推论:n的约数个数 = (a + 1)(b + 1)…(y + 1),(求出数n的因子个数)
# a+1是因为a^0,a^1,a^2
def prime_factor_decompose(n): # 质因数分解
i = 2
res = []
while i <= n:
if n % i == 0:
res.append(i)
n //= i
else:
i += 1
print(res)
prime_factor_decompose(12)
# 阶乘约数: 求100!有多少正约数
n = 100
p = [2]
for i in range(3, n+1): # 得到100以内的质数
j = 2
while i > j:
if i % j == 0:
break
j += 1
else:
p.append(i)
m = {} # 储存100!的每个质因子个数+1
for i in p:
m[i] = 1
for i in range(2,n+1):
for j in p:
if j > i:
break
while i % j == 0:
m[j] += 1
i //= j
s = 1
for i in m.values():
s *= i
print(s)
回溯,dfs,bfs
"""
def backtracking(参数):
if (终止条件) :
存放结果
return
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) :
处理节点
backtracking(路径,选择列表) // 递归
回溯,撤销处理结果
"""
"""
def dfs(参数):
if (越界不合法情况):
return
if (终点边界,输出答案):
return
for (循环枚举所有方案):
if(未被标记): # if (越界不合法情况): 也可以放这一块写
(标记)
dfs(下一层)
(还原标记) #回溯
"""
"""
#M:map地图 G:go走过路径 q=deque():双向队列 q.popleft() 头节点从左边出队
from collections import deque #导入数据结构deque
q=deque([(0,0)]) #1.化队列,迷宫开始位置坐标(0,0)
n,m=map(int,input().split())
M=[[int(i) for i in input()] for j in range(n)] #模拟地图
G=[['']*m for i in range(n)] #记录到从起点到该点走过路径的方向(根据题意设置)
while q:
x,y=q.popleft()
if x==n-1 and y==m-1: #2.设置结束条件,输出答案
print(len(G[-1][-1]))
print(G[-1][-1])
break
for i,j,k in [(1,0,'D'),(0,-1,'L'),(0,1,'R'),(-1,0,'U')]:#3.下一步路,遍历可以走的四个方向,得到下一个坐标(a,b)。
a,b=x+i,y+j
if 0<=a<n and 0<=b<m and M[a][b]==0: #3.判断合理,判断坐标是否越界,是否之前遍历过。
M[a][b]=1
q.append((a,b))#4.迭代赋值:判断合理就进行标记,然后添加到队列最后,路径表上增加此刻的方向。
G[a][b]=G[x][y]+k
"""
# 难题109 分考场
n = int(input())
m = int(input())
num = 110
p = [[0] * (n+1) for _ in range(n+1)] # p[i][j]=y 第i个考场的第j个座位,坐第y个人
a = [[0] * (n+1) for _ in range(n+1)] # a[i][j]=1 第i个人和第j个人认识
for i in range(m):
v, u = map(int, input().split())
a[v][u] = a[u][v] = 1
def dfs(x, room): # 第x个人,第room间考场
global num
if room > num: # 已经大于记录中的最小考场数,剪枝
return
if x > n: # 学生全部分配完毕
if room < num: # 更新最少考场数
num = room
return
for j in range(1, room+1):
k = 0
while p[j][k] and a[x][p[j][k]] == 0: # j考场的k座位有人坐,且这个人不认识第x个人
k += 1
if p[j][k] == 0: # 确保上一个while退出的条件是j考场k座位是空的,而不是因为这个人认识第x个人,如果是后者那么这里应该是某个学生的编号
p[j][k] = x
dfs(x+1, room) # 接着下一个学生,不用增加考场
p[j][k] = 0
p[room+1][0] = x
dfs(x+1, room+1) # 如果提前从上面的dfs出来,即x学生在每个教室都有熟人,就增加room数量
p[room+1][0] = 0
dfs(1, 0)
print(num)
迷宫问题(dfs,bfs)
# # dfs
# import sys
#
#
# sys.setrecursionlimit(999999)
#
#
# def dfs(startx, starty, step):
# global min_step
# if startx == x2 and starty == y2:
# if step < min_step:
# min_step = step
# return
# for i in range(4):
# if sign[startx + dirs[i][0]][starty + dirs[i][1]] == 0 and road[startx + dirs[i][0]][starty + dirs[i][1]] == 1:
# sign[startx + dirs[i][0]][starty + dirs[i][1]] = 1
# dfs(startx + dirs[i][0], starty + dirs[i][1], step + 1)
# sign[startx + dirs[i][0]][starty + dirs[i][1]] = 0
#
#
# n, m = map(int, input().split())
# road = [[0] * 120 for i in range(120)]
# for i in range(1, n + 1):
# ls = list(map(int, input().split()))
# for j in range(1, m + 1):
# road[i][j] = ls[j - 1]
# x1, y1, x2, y2 = map(int, input().split())
# sign = [[0] * 120 for i in range(120)]
# dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]]
# min_step = 999999
# dfs(x1, y1, 0)
# print(min_step)
#
#
# # bfs
# n, m = map(int, input().split())
# mp = [list(map(int, input().split())) for i in range(n)]
# dirs = [[1, 0], [-1, 0], [0, 1], [0, -1]]
# x1, y1, x2, y2 = map(int, input().split())
# q = [[x1 - 1, y1 - 1, 0]]
# f = True
# while q:
# x, y, dis = q.pop(0)
# if x == x2 - 1 and y == y2 - 1:
# f = False
# print(dis)
# break
# for xx, yy in dirs:
# tx, ty = xx + x, yy + y
# if 0 <= tx < n and 0 <= ty < m and mp[tx][ty] == 1:
# mp[tx][ty] = 0
# q.append([tx, ty, dis+1])
# if f:
# print(-1)
def dfs(startx, starty, step):
global min_step, flag
if startx == x2 and starty == y2:
if step < min_step:
min_step = step
flag = False
return
for i in range(4):
tx = startx + dirs[i][0]
ty = starty + dirs[i][1]
if 0 <= tx < n and 0 <= ty < m:
if road[tx][ty] == 1 and vis[tx][ty] == 0:
vis[tx][ty] = 1
dfs(tx, ty, step + 1)
vis[tx][ty] = 0
def bfs(startx, starty, step):
global queue, flag, min_step
while queue:
startx, starty, step = queue[0]
if startx == x2 and starty == y2:
min_step = step
break
for i in range(4):
tx = startx + dirs[i][0]
ty = starty + dirs[i][1]
if 0 <= tx < n and 0 <= ty < m:
# if road[tx][ty] == 1:
# road[tx][ty] = 0
if road[tx][ty] == 1 and vis[tx][ty] == 0:
vis[tx][ty] = 1
queue.append([tx, ty, step + 1])
queue.pop(0)
else: # break没有正常执行,也就是while正常退出没有遇到break强行退出
flag = False
n, m = map(int, input().split())
# road = [input().split() for i in range(n)] # 错误写法,二位列表中的一维列表每一项是字符串而不是数字
road = [list(map(int, input().split())) for _ in range(n)] # 1路0障碍
x1, y1, x2, y2 = [int(i)-1 for i in input().split()]
vis = [[0 for i in range(m)] for j in range(n)] # 1标记0未标记
dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]]
min_step = float('inf') # 无限大,float('-inf')无穷小
flag = True # 能否到达终点
# dfs(x1, y1, 0)
# if not flag:
# min_step = -1
# print(min_step)
queue = [[x1, y1, 0]]
bfs(x1, y1, 0)
if not flag:
min_step = -1
print(min_step)
并查集,最小生成树
def find(i):
if fa[i] == i: # 递归出口
return i
else:
return find(fa[i]) # 不断向上查找祖先
def union(i, j):
i_fa = find(i)
j_fa = find(j)
fa[i_fa] = fa[j_fa]
n = 10
fa = [i for i in range(n+1)]
# union(4, 3)
# union(4, 5)
# print(fa)
edge = [] # edge[i]=[a,b,c]代表i这条边连接了a,b,权值为c
ans = 0 # 权值和
edge.sort(key=lambda x: x[2]) # 按边权升序排序
for x in edge: # 遍历所有边
a, b, c = x[0], x[1], x[2]
if find(a) != find(b) and j <= n - 1: # 两顶点不连通且当前边数小于n-1
ans += x[2] # 权值累加
union(a, b)
j += 1
print(ans)
def find_compress(i): # 路径压缩
if fa[i] == i:
return i
else:
fa[i] = find(fa[i]) # 该步进行了路径压缩
return fa[i] # 返回父节点
# 1135 蓝桥幼儿园
def init_set(x):
return list(range(x+1))
def find_set(x):
# if stu[x] == x:
# return x
# else:
# return find_set(stu[x])
"""路径压缩"""
if stu[x] != x:
stu[x] = find_set(stu[x])
return stu[x]
def merge_set(i, j):
i_fa = find_set(i)
j_fa = find_set(j)
stu[i_fa] = stu[j_fa]
n, m = map(int, input().split())
stu = init_set(n)
for i in range(m):
op, x, y = map(int, input().split())
if op == 1:
merge_set(x, y)
elif op == 2:
# if find_set(x) == find_set(y):
# print("YES")
# else:
# print("NO")
print("YES") if find_set(x) == find_set(y) else print("NO")
# 595 七段码
# a b c d e f g
# 1 2 3 4 5 6 7
N = 10
e = [[0] * N for i in range(N)] # e[i][j]表示i和j是连着的(灯管图)
s = [0] * N # 并查集
vis = [0] * N # 1表示某个灯点亮了
ans = 0
def init():
global s
s = list(range(N))
def find_set(x):
if s[x] != x:
s[x] = find_set(s[x])
return s[x]
def merge_set(x, y):
x = find_set(x)
y = find_set(y)
if x != y:
s[x] = s[y]
def check():
global ans
init()
for i in range(1, 8):
for j in range(1, 8):
if e[i][j] == 1 and vis[i] == 1 and vis[j] == 1: # i和j相连并且全部点亮
merge_set(i, j)
flag = 0
for j in range(1, 8):
if vis[j] == 1 and s[j] == j: # 点亮过的灯全部连接
flag += 1
if flag == 1: # 必须等于1保证所有数的连通,大于1也是有两个以上不连通的,因为默认值s[i]=i,只有·访问到的灯全部连接在一起,才会出现flag=1的情况
ans += 1
def dfs(k):
if k == 8:
check()
else:
vis[k] = 1
dfs(k+1)
vis[k] = 0
dfs(k+1)
e[1][2] = e[1][6] = 1
e[2][1] = e[2][3] = e[2][7] = 1
e[3][2] = e[3][4] = e[3][7] = 1
e[4][3] = e[4][5] = 1
e[5][4] = e[5][6] = e[5][7] = 1
e[6][1] = e[6][5] = e[6][7] = 1
e[7][2] = e[7][3] = e[7][5] = e[7][6] = 1
dfs(1)
print(ans)
快速幂
from call_time import *
@call_time
def violence(base, power, mod=1):
print(base ** power % mod)
@call_time
def quick_drop_power(base, power, mod=1):
res = 1
while power > 0:
if power & 1:
res = res * base % mod
power -= 1
else:
base = base ** 2 % mod
power >>= 1
print(res)
base = 18
power = 1800000
mod = 2422424
violence(base, power, mod)
quick_drop_power(base, power, mod)
手写排列组合
a = [1, 2, 3, 4]
def dfs(s, t):
"""改变输出个数就s==3,print(*a[:3])"""
if s == t:
print(*a)
return
for i in range(s, t+1):
a[s], a[i] = a[i], a[s]
dfs(s+1, t)
a[s], a[i] = a[i], a[s]
dfs(0, 2)
# 上述也可以通过标记法得到,见p142
# 部分代码如下
# a = [1, 2, 3, 4]
# vis = [0] * 20 标记是否访问
# b = [0] * 20 生成一个全排列
# for i in range(t):
# if !vis[i]:
# vis[i] = True
# b[s] = a[i]
# dfs(s+1, t)
# vis[i] = False
# 生成二进制排列
vis = [0] * 10
def dfs(k):
global cnt
if k == 3:
for i in range(3):
print(vis[i], end='')
print('-', end='')
else:
vis[k] = 0
dfs(k+1)
vis[k] = 1
dfs(k+1)
dfs(0)
简单递推dp
背包问题
# total_weight, n = map(int, input().split())
# goods = [list(map(int, input().split())) for i in range(n)] # 0重量,1价值
w = [0] + [1, 2, 4, 6] # 重量
v = [0] + [2, 5, 6, 9] # 价值
total_weight, n = 10, 4
# ---------------------------------------------------------------
# 01背包(二维)
dp = [[0] * (total_weight + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
for j in range(1, total_weight + 1):
if w[i] > j:
dp[i][j] = dp[i - 1][j]
else:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i])
# print(dp)
print(dp[-1][-1])
# 01背包(一维滚动数组)
dp = [0] * (total_weight + 1)
for i in range(1, n + 1):
for j in range(total_weight, w[i] - 1, -1):
dp[j] = max(dp[j], dp[j - w[i]] + v[i])
print(dp[-1])
# 完全背包(二维)
dp = [[0] * (total_weight + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
for j in range(1, total_weight + 1):
dp[i][j] = dp[i - 1][j]
if j >= w[i]:
dp[i][j] = max(dp[i][j], dp[i][j - w[i]] + v[i])
print(dp[-1][-1])
# 完全背包(一维滚动数组)
dp = [0] * (total_weight + 1)
for i in range(1, n + 1):
for j in range(w[i], total_weight + 1):
dp[j] = max(dp[j], dp[j - w[i]] + v[i])
print(dp[-1])
# 多重背包(一维滚动数组)
w = [0] + [1, 2, 4, 6] # 重量
v = [0] + [2, 5, 6, 9] # 价值
g = [0] + [1, 2, 2, 1] # 每件物品个数
dp = [0] * (total_weight + 1)
for i in range(1, n + 1):
for k in range(1, g[i] + 1):
for j in range(total_weight, w[i] - 1, -1):
dp[j] = max(dp[j], dp[j - w[i]] + v[i])
print(dp[-1])
最长上升子序列,长度
n = int(input())
ls = list(map(int, input().split()))
dp = [1] * n
for i in range(n):
for j in range(i):
if ls[j] < ls[i]:
dp[i] = max(dp[i], dp[j] + 1)
# 到这一步已经完成了上升子数列的最大长度计算
dp_max = max(dp)
index = dp.index(dp_max)
lst = [0] * dp_max
lst[-1] = ls[index]
for i in range(index, -1, -1):
if ls[i] < ls[index] and dp[i] == dp[index] - 1:
dp_max -= 1
lst[dp_max - 1] = ls[i]
index = i
print(*lst)
最长公共子序列,长度
# str1 = "acbcbcef"
# str2 = "abcbced"
str1 = input()
str2 = input()
M = [[0 for i in range(len(str1) + 1)] for i in range(len(str2) + 1)]
xmax = 0
xindex = []
for i in range(1, len(str2) + 1):
for j in range(1, len(str1) + 1):
if str2[i - 1] == str1[j - 1]:
M[i][j] = M[i - 1][j - 1] + 1
if M[i][j] > xmax:
xmax = M[i][j]
xindex = [(i, j)]
elif M[i][j] == xmax:
xindex.append((i, j))
lcstr = ",".join([str2[i - xmax:i] for i, j in xindex])
print(lcstr)
最长回文子序列,长度
# 暴力 O(n^3)
# def longest_palindrome_subsequence(ls):
# global longest_palindrome, longest_palindrome_sub
# for i in range(len(ls)):
# for j in range(i+1, len(ls)):
# if is_palindrome(ls[i:j+1]) and len(ls[i:j+1]) > longest_palindrome:
# longest_palindrome = len(ls[i:j+1])
# longest_palindrome_sub = ls[i:j+1]
#
#
# def is_palindrome(ls):
# low = 0
# high = len(ls)-1
# flag = True
# while low < high:
# if ls[low] == ls[high]:
# low += 1
# high -= 1
# else:
# flag = False
# break
# return flag
#
#
# longest_palindrome = 0
# longest_palindrome_sub = ""
# ls = input()
# longest_palindrome_subsequence(ls)
# print(longest_palindrome_sub, longest_palindrome, sep='\n')
# O(n^2)
def longest_palindrome_subsequence(ls):
current_longest_subset = [0, 1] # 当前回文串下标区间
for i in range(1, len(ls)):
odd = long_sub(ls, i - 1, i + 1) # 奇数情况
even = long_sub(ls, i - 1, i) # 偶数情况
longest_sub = max(odd, even, key=lambda x: x[1] - x[0])
current_longest_subset = max(current_longest_subset, longest_sub, key=lambda x: x[1] - x[0])
return (ls[current_longest_subset[0]:current_longest_subset[1]],
current_longest_subset[1] - current_longest_subset[0])
def long_sub(ls, left, right):
while left >= 0 and right <= len(ls) - 1:
if ls[left] != ls[right]:
break
left -= 1
right += 1
return [left + 1, right] # left多减了一次, right取不到相当于right-1
ls = input()
string, length = longest_palindrome_subsequence(ls)
print(string, length, sep='\n')
树状数组和lowbit
# 序列是动态变化的,修改数组和查询区间轮流就行,就用树状数组,O(nlogn)
N = 1000
tree = [0] * N
lowbit = lambda x: x & -x
def update(x, d):
while x <= N:
tree[x] += d
x += lowbit(x)
def sum(x):
ans = 0
while x > 0:
ans += tree[x]
x -= lowbit(x)
return ans
a = [0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
for i in range(1, 11):
update(i, a[i])
print(sum(8) - sum(4))
update(5, 100)
print(sum(8) - sum(4))
约瑟夫环递推公式
def f(n, m): # n个人,编号0~n-1,每次数到m出列
last = 0
for i in range(2, n+1):
last = (last+m) % i
return last + 1 # 实际编号1~n
res = f(11, 3)
print(res)
质数埃筛
from call_time import *
@call_time
def enum_primes(n):
primes = []
for i in range(2, n):
for j in range(2, int(i ** 0.5)+1):
if i % j == 0:
break
else:
primes.append(i)
# print(primes)
@call_time
def get_primes_1(n):
primes = []
sieves = [True] * (n + 1)
sieves[0] = sieves[1] = False
p = 2
while p ** 2 <= n:
if sieves[p]:
for i in range(p * p, n+1, p):
sieves[i] = False
p += 1
for i in range(n+1):
if sieves[i]:
primes.append(i)
# print(primes)
@call_time
def get_primes_2(n):
primes = []
sieves = [True] * (n + 1)
for i in range(2, n):
if sieves[i]:
primes.append(i)
for j in range(i * i, n, i):
sieves[j] = False
print(primes)
n = 10000
enum_primes(n)
get_primes_1(n) # 最优
get_primes_2(n)