当前位置: 首页 > news >正文

蓝桥杯python组备赛(记录个人模板)

文章目录

  • 队列
  • 递归装饰器
  • 并查集
  • 树状数组
  • 线段树
  • 最近公共祖先LCA
  • ST表
  • 字典树
  • KMP
  • manacher
  • 跳表(代替C++ STL的set)
  • dijkstra
  • 总结

list代替

队列

deque双端队列替代

heapq

递归装饰器

众所周知,python的递归深度只有1000,根本满足不了大部分1e5以上的数据,当然你可以使用sys.setrecursionlimit(1000000)扩到1e6,但是这会增加空间消耗,在一些竞赛OJ如codeforces,甚至你还没开始写就爆空间了,甚至会出现莫名其妙的段错误,因此尽可能少用。取而代之的是手写栈,但是手写栈有个问题就是像在写汇编代码,使用装饰器模拟递归栈,就可以正常写递归不怕爆栈了

def bootstrap(func, stk=[]):
    def wrapper(*args, **kwargs):
        if stk:  # 递归一层返回
            return func(*args, **kwargs)
        else:
            # 遍历生成器函数
            gen = func(*args, **kwargs)
            while True:
                if type(gen) is GeneratorType:  # 新的生成器函数
                    stk.append(gen)  # 入栈
                    gen = next(gen)  # 递归
                else:  # 没有新的生成器函数
                    stk.pop()  # 弹出递归入口
                    if not stk:  # 全部遍历完了
                        break
                    gen = stk[-1].send(gen)
            return gen  # 返回答案
    return wrapper

不带返回值的调用,函数return改成yield,调用dfs需要加上yield

def solve():
    @bootstrap
    def dfs(n):
        print(n)
        if n==0:
            yield
        yield dfs(n-1)
        yield

带返回值的调用,经过实践可以修改装饰器代码使其带返回值,但是很容易出错,因此如果需要返回值,建议直接丢一个list到参数里面返回,因为list传的是引用

def solve():
    @bootstrap
    def dfs(n,rval):
        if n==0:
            rval.append(0)
            yield
        ans=[]
        yield dfs(n-1,ans)
        rval.append(ans[0]+1)   
        yield

    ans=[]

    dfs(5,ans)
    print(ans[0]) # 5

并查集

class DSU:
    def __init__(self,n):
        self.par=[i for i in range(n+1)]
        self.siz=[1]*(n+1)
    
    def find(self,x):
        if self.par[x]!=x:
            self.par[x]=self.find(self.par[x])
        return self.par[x]
    
    def merge(self,x,y):
        x=self.find(x)
        y=self.find(y)
        if x==y:
            return False
        self.par[y]=x
        self.siz[x]+=self.siz[y]
        return True
    
    def same(self,x,y):
        return self.find(x)==self.find(y)

树状数组

class Fenwick:
    def __init__(self,n):
        self.n=n
        self.t=[0]*(n+1)
    
    def add(self,x,y):
        while x<=self.n:
            self.t[x]+=y
            x+=x&-x
    
    def query(self,x):
        ans=0
        while x:
            ans+=self.t[x]
            x-=x&-x
        return ans

线段树

class SegmentTree:
    class Node:
        def __init__(self,val=0):
            self.sum=val
            self.tag=0
        def __add__(self,t):
            return SegmentTree.Node(self.sum+t.sum)
    
    def __init__(self, n, default=Node()):
        self.n=n
        self.t=[default]*(n<<2)

    def pushup(self,p):
        self.t[p]=self.t[p<<1]+self.t[p<<1|1]

    def pushtag(self,p,tag,l,r):
        self.t[p].tag+=tag
        self.t[p].sum+=(r-l+1)*tag


    def pushdown(self,p,l,mid,r):
        if self.t[p].tag:
            self.pushtag(p<<1,self.t[p].tag,l,mid)
            self.pushtag(p<<1|1,self.t[p].tag,mid+1,r)
            self.t[p].tag=0

    def build(self,p,l,r):
        if l==r:
            self.t[p]=self.Node()
            return
        mid=l+r>>1
        self.build(p<<1,l,mid)
        self.build(p<<1|1,mid+1,r)
        self.pushup(p)

    def modify(self,p,l,r,ql,qr,x):
        if(ql<=l and r<=qr):
            self.pushtag(p,x,l,r)
            return
        mid=l+r>>1
        self.pushdown(p,l,mid,r)
        if ql<=mid:
            self.modify(p<<1,l,mid,ql,qr,x)
        if qr>mid:
            self.modify(p<<1|1,mid+1,r,ql,qr,x)
        self.pushup(p)
    
    def modify(self,p,l,r,x,y):
        if l==r:
            self.t[p].sum+=y
            return
        mid=l+r>>1
        self.pushdown(p,l,mid,r)
        if x<=mid:
            self.modify(p<<1,l,mid,x,y)
        else:
            self.modify(p<<1|1,mid+1,r,x,y)
        self.pushup(p)
    
    def query(self,p,l,r,ql,qr):
        if ql<=l and r<=qr:
            return self.t[p]
        mid=l+r>>1
        self.pushdown(p,l,mid,r)
        ans=self.Node()
        if ql<=mid:
            ans+=self.query(p<<1,l,mid,ql,qr)
        if qr>mid:
            ans+=self.query(p<<1|1,mid+1,r,ql,qr)
        return ans

最近公共祖先LCA

N=int(1e5+10)
adj=[[] for _ in range(N)]
par=[[0]*30 for _ in range(N)]
dep=[0]*N

def dfs(u,fa):
    par[u][0]=fa
    dep[u]=dep[fa]+1
    for i in range(1,dep[u].bit_length()):
        par[u][i]=par[par[u][i-1]][i-1]
    for v in adj[u]:
        if v==fa: continue
        dfs(v,u)

def lca(x,y):
    if dep[x]<dep[y]:x,y=y,x
    while(dep[x]!=dep[y]):
        x=par[x][(dep[x]-dep[y]).bit_length()-1]
    if x==y: return x
    for i in range(dep[x].bit_length()-1,-1,-1):
        if par[x][i]!=par[y][i]:
            x=par[x][i]
            y=par[y][i]
    return par[x][0]

ST表

class SparseTable:
    def __init__(self,a,n):
        self.n=n
        self.m=n.bit_length()
        self.st=[[0]*self.m for _ in range(n+1)]
        for i in range(1,n+1):
            self.st[i][0]=a[i]
        for j in range(1,self.m):
            for i in range(1,n+1):
                if i+(1<<j)-1>n:break
                self.st[i][j]=max(self.st[i][j-1],self.st[i+(1<<j-1)][j-1])
    
    def query(self,l,r):
        j=(r-l+1).bit_length()-1
        return max(self.st[l][j],self.st[r-(1<<j)+1][j])

字典树

class Trie:
    def __init__(self,n):
        self.tr=[[0]*26 for _ in range(n*26)]
        self.idx=0
        self.cnt=[0]*(n*26)

    def insert(self,s):
        p=0
        for c in s:
            c=ord(c)-ord('a')
            if not self.tr[p][c]:
                idx+=1
                self.tr[p][c]=self.idx
            p=self.tr[p][c] 
        
        self.cnt[p]+=1 
        
    def query(self,s):
        p=0
        for c in s:
            c=ord(c)-ord('a')
            if not self.tr[p][c]:
                return 0 
            p=self.tr[p][c] 
        return self.cnt[p]

KMP

def kmp(s):
    n = len(s)
    nxt = [0] * n
    j = 0
    for i in range(1, n):
        while j > 0 and s[i] != s[j]:
            j = nxt[j - 1]
        if s[i] == s[j]:
            j += 1
        nxt[i] = j
    return nxt

manacher

def manacher(s):
    s = '#' + '#'.join(s) + '#'
    n = len(s)
    p = [0] * n
    r, c = 0, 0
    for i in range(n):
        if i < r:
            p[i] = min(r - i, p[2 * c - i])
        while i - p[i] >= 0 and i + p[i] < n and s[i - p[i]] == s[i + p[i]]:
            p[i] += 1
        if i + p[i] > r:
            r = i + p[i]
            c = i
    return p

跳表(代替C++ STL的set)

感觉是目前最好的平替了,其他平衡树要么太难写没必要,像无旋平衡树这种常数又太大,跳表应该是最好的选择了

MAX_LEVEL = 32
P_FACTOR = 0.25

def random_level() -> int:
    lv = 1
    while lv < MAX_LEVEL and random.random() < P_FACTOR:
        lv += 1
    return lv

class SkiplistNode:
    __slots__ = 'val', 'forward'

    def __init__(self, val: int, max_level=MAX_LEVEL):
        self.val = val
        self.forward = [None] * max_level

class Skiplist:
    def __init__(self):
        self.head = SkiplistNode(-1)
        self.level = 0

    def search(self, target: int) -> bool:
        curr = self.head
        for i in range(self.level - 1, -1, -1):
            # 找到第 i 层小于且最接近 target 的元素
            while curr.forward[i] and curr.forward[i].val < target:
                curr = curr.forward[i]
        curr = curr.forward[0]
        # 检测当前元素的值是否等于 target
        return curr is not None and curr.val == target

    def add(self, num: int) -> None:
        update = [self.head] * MAX_LEVEL
        curr = self.head
        for i in range(self.level - 1, -1, -1):
            # 找到第 i 层小于且最接近 num 的元素
            while curr.forward[i] and curr.forward[i].val < num:
                curr = curr.forward[i]
            update[i] = curr
        lv = random_level()
        self.level = max(self.level, lv)
        new_node = SkiplistNode(num, lv)
        for i in range(lv):
            # 对第 i 层的状态进行更新,将当前元素的 forward 指向新的节点
            new_node.forward[i] = update[i].forward[i]
            update[i].forward[i] = new_node

    def erase(self, num: int) -> bool:
        update = [None] * MAX_LEVEL
        curr = self.head
        for i in range(self.level - 1, -1, -1):
            # 找到第 i 层小于且最接近 num 的元素
            while curr.forward[i] and curr.forward[i].val < num:
                curr = curr.forward[i]
            update[i] = curr
        curr = curr.forward[0]
        if curr is None or curr.val != num:  # 值不存在
            return False
        for i in range(self.level):
            if update[i].forward[i] != curr:
                break
            # 对第 i 层的状态进行更新,将 forward 指向被删除节点的下一跳
            update[i].forward[i] = curr.forward[i]
        # 更新当前的 level
        while self.level > 1 and self.head.forward[self.level - 1] is None:
            self.level -= 1
        return True

dijkstra

adj=[[] for _ in range(N)]
dis=[inf]*N
def dijkstra():
    dis[1]=0
    heap=[(0,1)] 
    while heap:
        d,x=heappop(heap)
        if dis[x]<d:continue
        for y,c in adj[x]:
            if d+c<dis[y]:
                dis[y]=d+c
                heappush(heap,(dis[y],y))

总结

省赛能用到的应该就这么多了,剩下的要么是思维,要么是模拟,要么是各种dp,后续进国赛再深度挖掘一下其他的模板

相关文章:

  • 【实践总结】如何编写“多角色适配”的高质量技术文档?
  • HTTP 教程 : 从 0 到 1 全面指南 教程【全文三万字保姆级详细讲解】
  • DiffSynth-Studio-视频的风格转换 CUDA日志
  • OpenCV--图像边缘检测
  • 临床 不等于 医学-《分析模式》漫谈52
  • 企业落地AI难的隐形枷锁-正是数据问题
  • C 变量:深入解析与高效使用
  • 《基于 std::vector 的简单本地注册登录系统设计与实现》
  • 用claude3.7,不到1天写了一个工具小程序(11个工具6个游戏)
  • 在PowerBI中通过比较日期实现累加计算
  • Python基础——Pandas库
  • vue2和vue3的主要区别
  • 【C语言】跳台阶
  • Vue2 快速过度 Vue3 教程 (后端学习)
  • NO.68十六届蓝桥杯备战|基础算法-离散化|火烧赤壁|贴海报(C++)
  • 深圳漫云科技户外公园实景儿童剧本杀小程序:开启亲子互动新纪元
  • Windows下使用sshfs挂载远程文件夹及挂载问题解决方案
  • windows11在连接第二屏幕之后没有声音问题
  • 基于RPA的IT运维服务方案
  • JAVA类和对象
  • 梅州网站建设公司/网站诊断分析
  • 石家庄人力资源和社会保障局/二十条优化疫情措施
  • 衡水哪有做网站的/软文街官网
  • 网站服务器哪里的好/百度推广案例及效果
  • 马云做的国外的网站叫什么名字/阜阳seo
  • 网站推广怎么优化/网站建设关键词排名