python模板(备战蓝桥国赛)

目录

bisect

functools.cmp_to_key

gcd和lcm

二分

倍增法(ST)

前缀和,差分

区间合并

双指针(尺取法)

唯一分解定理和质因数分解

回溯,dfs,bfs

迷宫问题(dfs,bfs)

并查集,最小生成树

快速幂

手写排列组合

简单递推dp

背包问题

最长上升子序列,长度

最长公共子序列,长度

最长回文子序列,长度

树状数字和lowbit

约瑟夫环递推公式

质数埃筛


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)

  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值