From c56b3c7ed3d6872e0bf0f378b6e6143c87afb04a Mon Sep 17 00:00:00 2001 From: lanthanine <2300011713@stu.pku.edu.cn> Date: Tue, 3 Jun 2025 23:03:56 +0800 Subject: [PATCH] Add files via upload --- cheatsheet/cheatsheet/cheatsheet_basic.py | 412 +++++++++++ .../cheatsheet_dynamic_programming.py | 386 ++++++++++ cheatsheet/cheatsheet/cheatsheet_graph.py | 514 +++++++++++++ .../cheatsheet/cheatsheet_recursion&dp.py | 248 +++++++ .../cheatsheet/cheatsheet_search&sorting.py | 521 ++++++++++++++ cheatsheet/cheatsheet/cheatsheet_tree.py | 678 ++++++++++++++++++ cheatsheet/cheatsheet/wangnianti.py | 366 ++++++++++ 7 files changed, 3125 insertions(+) create mode 100644 cheatsheet/cheatsheet/cheatsheet_basic.py create mode 100644 cheatsheet/cheatsheet/cheatsheet_dynamic_programming.py create mode 100644 cheatsheet/cheatsheet/cheatsheet_graph.py create mode 100644 cheatsheet/cheatsheet/cheatsheet_recursion&dp.py create mode 100644 cheatsheet/cheatsheet/cheatsheet_search&sorting.py create mode 100644 cheatsheet/cheatsheet/cheatsheet_tree.py create mode 100644 cheatsheet/cheatsheet/wangnianti.py diff --git a/cheatsheet/cheatsheet/cheatsheet_basic.py b/cheatsheet/cheatsheet/cheatsheet_basic.py new file mode 100644 index 00000000..2c3fc1cc --- /dev/null +++ b/cheatsheet/cheatsheet/cheatsheet_basic.py @@ -0,0 +1,412 @@ +''' +有关 sys 模块 +''' +def main(): + import sys + + #单行单个数据 + n=int(sys.stdin.readline().strip()) #整数 + s=sys.stdin.readline().strip() #字符串 + + #单行多个数据 + arr=list(map(int,sys.stdin.readline().split())) + + #一次性读取所有数据 + all_input=sys.stdin.read().strip() + lines=all_input.split("\n") + + #未知行数,可能包含空行,一次性读完所有数据,并储存进一个列表 + nums = [] + for line in sys.stdin: + for i in line.split(): + nums.append(int(i)) + + +''' +部分作业题 +''' +''' +P1748 Josephus Problem +''' +def josephus(n,k): + monkeys=[i for i in range(1,n+1)] + tps=0 + while len(monkeys)>1: + tps=(tps+k-1)%len(monkeys) + monkeys.remove(monkeys[tps]) + return monkeys[0] + +mission=[] +while True: + lst=list(map(int,input().split())) + if lst[0]==0: + break + mission.append(lst) + +for i in range(len(mission)): + print(josephus(mission[i][0],mission[i][1])) + +''' +螺旋加密 +''' +#5. 螺旋加密 +def password(m,n,s): + ans="" + for i in s: + if i==" ": + ans+="00000" + else: + cache=ord(i)-ord("A")+1 + cache=(bin(cache))[2:] + cache=f'{cache:0>5}' + ans+=cache + ans+="0"*(m*n-len(s)*5) + return ans + +def sprial_matrix(m,n,ans): + matrix=[[0]*n for _ in range(m)] + num=0 + left,right,top,bottom=0,n-1,0,m-1 + while left<=right and top<=bottom: + #从左到右遍历上边界 + for i in range(left,right+1): + matrix[top][i]=ans[num] + num+=1 + top+=1 + + #从上到下遍历右边界 + for i in range(top,bottom+1): + matrix[i][right]=ans[num] + num+=1 + right-=1 + + #从右到左遍历下边界 + for i in range(right,left-1,-1): + matrix[bottom][i]=ans[num] + num+=1 + bottom-=1 + + #从下到上遍历左边界 + for i in range(bottom,top-1,-1): + matrix[i][left]=ans[num] + num+=1 + left+=1 + return matrix + +''' +7207 神奇的幻方 +''' +from mpl_toolkits.mplot3d.art3d import poly_collection_2d_to_3d + + +def magic_square(n): + matrix=[[0]*(2*n-1)for _ in range(2*n-1)] + i=1 + j,k=0,n-1 + while i<=(2*n-1)**2: + matrix[j][k]=i + i+=1 + if j==0 and k==2*n-2: + j,k=1,2*n-2 + elif j==0: + j,k=2*n-2 , k+1 + elif k==2*n-2: + j,k=j-1,0 + elif matrix[j-1][k+1]!=0: + j+=1 + else: + j,k=j-1,k+1 + return matrix +''' +n=int(input()) +matrix=magic_square(n) +tps=0 +while tps<2*n-1: + print(" ".join(map(str,matrix[tps]))) + tps+=1 +''' + +''' +题目复盘:行列式的指标可以用row(行),col(列) +中间判定的代码可以狠狠简化,row+1超限返回0,相当于对方阵行列数size取余 +修改代码如下: +''' +def approved_magic_square(n): + size=2*n-1 + matrix=[[0]*size for _ in range(size)] + i=1 + row,col=0,n-1 + while i<=size**2: + matrix[row][col]=i + i+=1 + new_row,new_col=(row+1)%size,(col+1)%size + if matrix[new_row][new_col]: + row+=1 + else: + row,col=new_row,new_col + return matrix + + +""" +21006 方苹果(盘子相同) +把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放, +问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。 +这是一道组合数学问题,可以用递归或动态规划实现 +""" +#以下是一种用动态规划实现的方法 +def count_ways_dp(n,m): + dp=[[0]*(m+1) for _ in range(n+1)] + for i in range(n+1): + dp[i][1]=1 + for j in range(1,m+1): + dp[0][j]=1 + for i in range(1,n+1): + for j in range(2,m+1): + if i=i+1: + if number[-i-1]=="1": + ans+=1 + return ans + +#以下是一个降低代码时间复杂度的方法,用到了掩码来判断二进制第i位是否为1 +def better_Q(numbers,i): + mask=1<>i&1)) + +shift=0 +output=[] +for k in range(len(operate)): + if operate[k][0]=="C": + d=int(operate[k][1]) + shift=(shift+d)%65536 + else: + i=int(operate[k][1]) + mask=1<numbers2[-1][1]: + item=numbers1.pop() + elif numbers2[-1][1]>numbers1[-1][1]: + item=numbers2.pop() + else: + coeff=numbers1[-1][0]-numbers2[-1][0] + exp=numbers1[-1][1] + numbers1.pop() + numbers2.pop() + if coeff!=0: + item=[coeff,exp] + else: + continue + #处理item项 + if item[0]==0: + continue + if ans and ans[-1][1]==item[1]: #这里得确保ans有元素,否则会越界 + ans[-1][0]+=item[0] + if ans[-1][0]==0: #每次进行加和操作后,都要注意检查系数是否为0 + ans.pop() + else: + ans.append(item) + return ans + +def format_polynomial(poly): + terms = [] + for power in poly: + terms.append("[ {} {} ]".format(power[0], power[1])) + return " ".join(terms) + +n=int(input()) +for i in range(n): + poly_1=[] + poly_2=[] + numbers_1=list(map(int,input().split())) + for i in range(0,len(numbers_1)-2,2): + poly_1.append([numbers_1[i],numbers_1[i+1]]) + numbers_2=list(map(int,input().split())) + for i in range(0,len(numbers_2)-2,2): + poly_2.append([numbers_2[i],numbers_2[i+1]]) + result=summation(poly_1,poly_2) + print(format_polynomial(result)) + + + + + +''' + elif numbers1[-1][1]==numbers2[-1][1]: + if numbers1[-1][0] + numbers2[-1][0] != 0: + ans.append([numbers1[-1][0]+numbers2[-1][0],numbers1[-1][1]]) + numbers1.pop() + numbers2.pop() + elif numbers1[-1][1]>numbers2[-1][1] and numbers1[-1][0]!=0: + if ans and numbers1[-1][1]==ans[-1][1]: + ans[-1][0]+=numbers1[-1][0] + if ans[-1][0]==0: + ans.pop() + numbers1.pop() + else: + ans.append(numbers1.pop()) + elif numbers1[-1][1]0的情况 + for j in range(1, i + 1): + dp[i][j] = dp[i][j - 1] + dp[i - j][j] + # 对于j超过i的情况,直接取j=i的值 + for j in range(i + 1, max_n + 1): + dp[i][j] = dp[i][i] + +import sys +for line in sys.stdin: + n = int(line.strip()) + print(dp[n][n]) + +''' +8780 最长单调递减子序列(LDS) +''' +#找到一段数组中长度最长的单调不增序列 +#经典问题:求最长非递增子序列长度 +#n=int(input()) +#height=tuple(map(int,input().split())) +def intercept_missiles(height,n): + dp=[1]*(n+1) #dp[i]表示第i个位置索引的元素是当前子序列中可能得最小子序列 + for i in range(n): + for j in range(i): #时间复杂度为O(N^2) + if height[i]<=height[j]: #只有后者高度小于前者才需要判断 + dp[i]=max(dp[j]+1,dp[i]) + #此时,前面第j个位置dp[j]已能反映出它之前可拦截的导弹数 + return max(dp[i] for i in range(n)) + +#print(intercept_missiles(height)) + +''' +20650 最长的公共子序列(LCS) +''' +#思路:在序列前加一个空格,来确定边界条件 +#定义一个二维数组lcs(i,j),表示字符串a中第i个字符和字符串b中第j个字符的LCS长度 +#if a[i]=b[j]: lcs[i][j]=lcs[i-1][j-1]+1 +#else: lcs[i][j]=max(lcs[i-1][j],lcs[i][j-1] 两个删去任意一个都可以,要比较两种情况 +def lps(str1,str2): + n=len(str1) + m=len(str2) + if n==0: + return 0 + else: + dp=[[0]*(n+1) for _ in range(m+1)] + #dp[i][j]表示str1[:i]与str[:j]的最长共子序列 + for i in range(1,n+1): + for j in range(1,m+1): + if str1[i-1]==str2[j-1]: + dp[i][j]=dp[i-1][j-1]+1 + else: + dp[i][j]=max(dp[i-1][j],dp[i][j-1]) + return dp[n][m] + + +''' +0-1背包问题 +问题描述:给定一组物品,每个物品有重量weight[i]与价值value[i],以及背包最大容量w +要求选择物品放入背包使总重量不超过w,且总价值最大 +''' +#dp[i][w]表示前i个物品中,选择重量不超过w的物品时能获得的最大价值 +#状态转移方程:dp[i][w]=max(dp[i-1][w],dp[i-1][w-weight[i-1]]+value[i-1]) +#初始化条件:dp[0][w]=0,dp[i][0]=0 + +def knapsack(weights,values,w): + n=len(weights) + dp=[[0]*(w+1) for _ in range(n+1)] + #初始化列表 + for i in range(1,n+1): + for w in range(w+1): + if weights[i-1]>w: + dp[i][w]=dp[i-1][w] + else: + #在选择与不选择当前物品之间做出选择,注意这里列表weights和values的指标都要-1 + dp[i][w]=max(dp[i-1][w],dp[i-1][w-weights[i-1]]+values[i-1]) + return dp[n][w] + + +''' +最长公共前后缀问题(LPS Longest Prefix Suffix) +问题描述:给定一个字符串,在该字符串中,找到最长的既是前缀又是后缀的真子串,并返回该子串 +''' +#模式值:代表当前字符串的最长公共前后缀长度 +#模式串:str[:i] for i in range(1,len(str)+1)构成的字符串 +#称str[:n]为str[:n+1]的基础串,s[j]为s[i:j]的后继字符 +#算法思路:考虑字符串s的基础串,t是它的lps,若s的末字符与t的后继字符相等,则t拼接上后继字符便是s的lps, +#否则t变成s短一点的公共前后缀 +def lps(str): + ret=[0]*len(str) #定义其模式串 + for i in range(1,len(str)): + j=ret[i-1] #意味着继承了基础串的公共子序列 + while True: + if str[j]==str[i]: #如果相等,基础串公共子序列+1 + ret[i]=j+1 + break + elif j==0: #该字符不相等且此前也没有公共前后缀,在该位置仍然没有前后缀 + ret[i]=0 + break + else: #该处不匹配,但前面已有公共前后缀,则向前考察一位,缩短子缀长度以提高其适配性 + j-=1 + return ret + +#print(lps(input())) + +''' +计算一维数组最大子数组和(全负范围) +使用算法:Kadane算法 +''' +def max_subarray(nums): + n=len(nums) + if n==0: + return 0 + max_end_here=nums[0] + max_so_far=nums[0] + for i in range(1,n): + max_end_here=max(nums[i],nums[i]+max_end_here) #比较:是此前所有项还是仅有当前项 + max_so_far=max(max_so_far,max_end_here) #比较:是上一个最优值还是这个最优值 + return max_so_far + +''' +这道题的背景是输出矩阵的最大子矩阵 +二维矩阵的最大子矩阵问题,可以通过生成双指针,遍历起终行的方式转换为一维数组的最大子数组 +''' +matrix=[[0,-2,-8,0],[9,2,-6,2],[-4,1,-4,1],[-1,8,0,2]] +for _ in range(1): + n=4 + max_num=-float("inf") + for i in range(n): #遍历起始行 + nums = [0] * n + for j in range(i,n): #遍历终止行 + for k in range(n): + nums[k]+=matrix[j][k] #遍历终止行 + so_far=max_subarray(nums) + if so_far>max_num: + max_num=so_far + print(max_num) + + +''' +作业题目 +''' + +''' +7215 简单的整数划分问题 +''' +# 递归方法 +def integer_partition(n,max_num): + if n==0: + return 1 + if n<0 or max_num==0: + return 0 + return integer_partition(n,max_num-1)+integer_partition(n-max_num,max_num) + +#动态规划方法 +def count_partition_dp(n): + dp=[[0]*(51) for _ in range(51)] + for i in range(n+1): + dp[0][i]=1 + for i in range(1,n+1): + for j in range(1,n+1): + if j<=i: + dp[i][j]=dp[i-j][j]+dp[i][j-1] + else: + dp[i][j]=dp[i][i] + return dp[n][n] + +#n=int(input()) +#print(integer_partition(n,n)) + +#???这个程序错在哪里?为什么wrong answer + + +''' +1775 采药 +''' + +#经典背包问题 +T,M=map(int,input().split()) +matrix=[tuple(map(int,input().split())) for _ in range(M)] +dp=[0]*(T+1) #初始化动归列表 + +for t,v in matrix: #从耗时最长的开始遍历:我能把它放进背包里吗? + for j in range(T,t-1,-1): #这一行判定我是否有足够时间 + dp[j]=max(dp[j],dp[j-t]+v) #这一行判定我花费时间摘草药是否值得 + +print(dp[T]) + + + +''' +8780 拦截导弹(LDS) +''' +#找到一段数组中长度最长的单调不增序列 +#经典问题:求最长非递增子序列长度 +#n=int(input()) +#height=tuple(map(int,input().split())) +def intercept_missiles(height,n): + dp=[1]*(n+1) #dp[i]表示第i个位置索引的导弹是可拦截的最后一个导弹 + for i in range(n): + for j in range(i): #时间复杂度为O(N^2) + if height[i]<=height[j]: #只有后者高度小于前者才需要判断 + dp[i]=max(dp[j]+1,dp[i]) + #此时,前面第j个位置dp[j]已能反映出它之前可拦截的导弹数 + return max(dp[i] for i in range(n)) + +#print(intercept_missiles(height)) + +''' +24375 小木棍 +''' +import math + + +def find_min_original_length(n, sticks): + if n == 0: + return 0 + total = sum(sticks) + max_len = max(sticks) + sticks.sort(reverse=True) + + # 收集所有因数,并筛选出>=max_len的候选 + factors = set() + for i in range(1, int(math.isqrt(total)) + 1): + if total % i == 0: + factors.add(i) + factors.add(total // i) + candidates = [x for x in factors if x >= max_len] + candidates.sort() + + for L in candidates: + if total % L != 0: + continue + k = total // L + if any(stick > L for stick in sticks): + continue + + # 预处理sum_from数组 + m = len(sticks) + sum_from = [0] * m + sum_from[-1] = sticks[-1] + for i in range(m - 2, -1, -1): + sum_from[i] = sum_from[i + 1] + sticks[i] + + used = [False] * m + + def backtrack(start, remain, count): + if count == 0: + return True + if remain == 0: + return backtrack(0, L, count - 1) + + # 找到第一个未使用的起始位置 + start_pos = start + while start_pos < m and used[start_pos]: + start_pos += 1 + if start_pos >= m: + return False + if sum_from[start_pos] < remain: + return False + + prev = -1 + for i in range(start_pos, m): + if used[i]: + continue + if sticks[i] > remain: + continue + if sticks[i] == prev: + continue + if i > 0 and sticks[i] == sticks[i - 1] and not used[i - 1]: + continue + + used[i] = True + prev = sticks[i] + success = backtrack(i + 1, remain - sticks[i], count) + used[i] = False + + if success: + return True + if remain == L: + return False + + return False + + if backtrack(0, L, k): + return L + + return total + + +import sys + +for line in sys.stdin: + n = int(line.strip()) + if n == 0: + break + sticks = list(map(int, sys.stdin.readline().split())) + print(find_min_original_length(n, sticks)) + + +''' +23997 奇数划分 +''' + +#回溯-递归解法 +ans=[] +def backtrack(start,remain,path): + if remain==0: + ans.append(path.copy()) + return + for i in range(start,remain+1,2): + if i>remain: + break + else: + path.append(i) + backtrack(i+2,remain-i,path) + path.pop() + +#n=int(input()) +#backtrack(1,n,[]) +#for i in ans: +# print(" ".join(map(str,i))) +#print(len(ans)) + +#动态规划算法 +#可以视作0-1背包问题的变种,不过从values最大值变成和为给定值 +#dp[i][j]表示前i个奇数是可以选择用或不用的,j是要凑出来的数值 + +def dp_backtrack(n): + odds=[i for i in range(1,n+1) if i%2==1] + m=len(odds) + dp=[[0]*(n+1) for _ in range(m+1)] + dp[0][0]=1 + for k in range(1,m+1): + j=odds[k-1] + for i in range(n+1): + dp[k][i]=dp[k-1][i] #如果不用当前第k个奇数 + if i>=j: #当前判定的奇数比需要表示的值更大,此时i-j>0,才有讨论用i的可能, + #否则我们在凑j时是不可能用i的 + dp[k][i]+=dp[k-1][i-j] + return dp[m][n] + +#n=int(input()) +#print(dp_backtrack(n)) + +''' +25815 回文字符串 +这里注意区分,如果只有增删两种操作,相当于最长回文子序列(LPS) +如果有增删改三种,显然改的效率大于增删,应该正向考虑这个问题 +''' +#类比最长公子序列 +def lps(str): + n=len(str) + if n==0: + return 0 + else: + dp=[[0]*(n) for _ in range(n)] + #dp[i][i]表示str[i……j]之间的最长回文子序列长度 + for i in range(n-1,-1,-1): + for j in range(i+1,n): + if str[i]==str[j]: + dp[i][j]=dp[i+1][j-1] + else: + dp[i][j]=min(1+dp[i+1][j],1+dp[i][j-1],1+dp[i+1][j-1]) + return dp[0][n-1] + +str=input().strip() +print(lps(str)) + + + diff --git a/cheatsheet/cheatsheet/cheatsheet_graph.py b/cheatsheet/cheatsheet/cheatsheet_graph.py new file mode 100644 index 00000000..e225cfa0 --- /dev/null +++ b/cheatsheet/cheatsheet/cheatsheet_graph.py @@ -0,0 +1,514 @@ +''' +基础知识 & 经典代码·1 +''' + +#ADT Graph的实现 +#包含两个类,VertBase用于记录顶点/顶点连接边的信息,Graph用于构造图,保存了包含所有顶点的主表 +class VertBase: + def __init__(self,key): + self.id=key + self.connectedTo={} + self.inDegree=0 + self.outDegree=0 + def addNeighbor(self,nbr,weight=1): + #添加从当前节点到nbr节点的有向边 + #添加重复边以增加其权值,不影响节点出入度 + if nbr not in self.connectedTo: + self.outDegree+=1 + nbr.inDegree+=1 + self.connectedTo[nbr]=weight + def delNeighbor(self,nbr): + if nbr in self.connectedTo: + self.outDegree-=1 + nbr.inDegree-=1 + del (self.connectedTo[nbr]) #为什么要加括号? + def __str__(self): + return f"{self.id}({self.inDegree}:{self.outDegree})" + + __repr__=__str__ + + def getConnection(self): + return self.connectedTo.keys() + def getId(self): + return self.id + def getWeight(self,nbr): + return self.connectedTo[nbr] + + #__str__可以在print(obj),str(obj)调用下,返回用户友好的节点状态描述 + #__repr__用于交互式环境/容器内对象显示,与__str__一致,便于调试 + +class Graph: + def __init__(self): + self.vertList={} + self.numVertices=0 + def addVertex(self,key): + self.numVertices+=1 + newVertice=VertBase(key) + self.vertList[key]=newVertice + return newVertice + def getVertex(self,n): + if n in self.vertList: + return self.vertList[n] + else: + return None + def __contains__(self,n): + return n in self.vertList #检测特定元素是否是图的顶点 + def addEdge(self,f,t,cost=0): + if f not in self.vertList: + nv=self.addVertex(f) + if t not in self.vertList: + nv=self.addVertex(t) + self.vertList[f].addNeighbor(self.vertList[t],cost) + + def getVertices(self): + return self.vertList.keys() + def __iter__(self): + return iter(self.vertList.values()) + +g=Graph() +for i in range(10): + g.addVertex(i) +g.addEdge(0,1,5) + +#广度优先搜索(BFS)与深度优先搜索(DFS) +#核心:表示出边的连接关系;设置一个列表反映该点是否被遍历过 +#Eg. 广度优先搜索 +''' +while queue: + cr,cc,time=queue.popleft() + for dr,dc in moves: + nr,nc=cr+dr,cc+dc + if 0<=nr<=r-1 and 0<=nc<=c-1 and not visited_mapp[nr][nc]: + if nr==er and nc==ec: + print(time+1) + found=True + break + elif mapp[nr][nc]: + visited_mapp[nr][nc]=1 + queue.append((nr,nc,time+1)) + if found: #这个判定很重要! + break + if not found: + print("oop!") +''' + +#无向带权图的最短路径问题:Dijkstra算法(边权非负) +import heapq + +def dijkstra(graph,start): + distances={node:int("inf") for node in graph} #保存了现有的起始点到终点的最短路径 + distances[start]=0 + + queue=[(0,start)] + while queue: + current_dist,current_node=heapq.heappop(queue) #弹出这条搜索路径下的路径之和 + if current_dist>distances[current_node]: + continue + for neighbor,weight in graph[current_node].items(): + distance=current_dist+weight + if distances[neighbor]>distance: + distances[neighbor]=distance + heapq.heappush(queue,(distance,neighbor)) + return distances + + +#无向带权图的最小生成树问题 +edges=[('A', 'B', 12), ('A', 'I', 25), ('B', 'C', 10), + ('B', 'H', 40), ('B', 'I', 8), ('C', 'D', 18), + ('C', 'G', 55), ('D', 'E', 44), ('E', 'F', 60), + ('E', 'G', 38), ('G', 'H', 35), ('H', 'I', 35)] +n=9 +node_index=[chr(ord("A")+i) for i in range(n)] + +edges.sort(key=lambda x:x[2]) +total_cost=0 +edge_count=0 + +#构建最小子树 +parent=[_ for _ in range(n)] #根节点列表初始化:每个结点独立 +rank=[0]*n #每个节点所在树的高度 + +def find(x): #寻找结点的根结点 + if parent[x]!=x: + parent[x]=find(parent[x]) + return parent[x] +def union(x,y): #按秩合并,总是将小树合并到大树下 + rx,ry=find(x),find(y) + if rx==ry: + return False + if rank[rx]distances[curr_r][curr_c]: + continue + if curr_c==tc and curr_r==tr: + print(distances[curr_r][curr_c]) + break + + for dr,dc in moves: + nr,nc=curr_r+dr,curr_c+dc + if 0<=nr<=r-1 and 0<=nc<=c-1 and mapp[nr][nc]: + curr_dist=distance+mapp[nr][nc] + if curr_distw: + dp[i][w]=dp[i-1][w] + else: + #在选择与不选择当前物品之间做出选择,注意这里列表weights和values的指标都要-1 + dp[i][w]=max(dp[i-1][w],dp[i-1][w-weights[i-1]]+values[i-1]) + return dp[n][w] + + +''' +最长公共前后缀问题(LPS Longest Prefix Suffix) +问题描述:给定一个字符串,在该字符串中,找到最长的既是前缀又是后缀的真子串,并返回该子串 +''' +#模式值:代表当前字符串的最长公共前后缀长度 +#模式串:str[:i] for i in range(1,len(str)+1)构成的字符串 +#称str[:n]为str[:n+1]的基础串,s[j]为s[i:j]的后继字符 +#算法思路:考虑字符串s的基础串,t是它的lps,若s的末字符与t的后继字符相等,则t拼接上后继字符便是s的lps, +#否则t变成s短一点的公共前后缀 +def lps(str): + ret=[0]*len(str) #定义其模式串 + for i in range(1,len(str)): + j=ret[i-1] #意味着继承了基础串的公共子序列 + while True: + if str[j]==str[i]: #如果相等,基础串公共子序列+1 + ret[i]=j+1 + break + elif j==0: #该字符不相等且此前也没有公共前后缀,在该位置仍然没有前后缀 + ret[i]=0 + break + else: #该处不匹配,但前面已有公共前后缀,则向前考察一位,缩短子缀长度以提高其适配性 + j-=1 + return ret + +#print(lps(input())) + + +''' +作业题目 +''' + +''' +7215 简单的整数划分问题 +''' +# 递归方法 +def integer_partition(n,max_num): + if n==0: + return 1 + if n<0 or max_num==0: + return 0 + return integer_partition(n,max_num-1)+integer_partition(n-max_num,max_num) + +#动态规划方法 +def count_partition_dp(n): + dp=[[0]*(51) for _ in range(51)] + for i in range(n+1): + dp[0][i]=1 + for i in range(1,n+1): + for j in range(1,n+1): + if j<=i: + dp[i][j]=dp[i-j][j]+dp[i][j-1] + else: + dp[i][j]=dp[i][i] + return dp[n][n] + +#n=int(input()) +#print(integer_partition(n,n)) + +#???这个程序错在哪里?为什么wrong answer + + +''' +1775 采药 +''' + +#经典背包问题 +T,M=map(int,input().split()) +matrix=[tuple(map(int,input().split())) for _ in range(M)] +dp=[0]*(T+1) #初始化动归列表 + +for t,v in matrix: #从耗时最长的开始遍历:我能把它放进背包里吗? + for j in range(T,t-1,-1): #这一行判定我是否有足够时间 + dp[j]=max(dp[j],dp[j-t]+v) #这一行判定我花费时间摘草药是否值得 + +print(dp[T]) + + + +''' +8780 拦截导弹(LDS) +''' +#找到一段数组中长度最长的单调不增序列 +#经典问题:求最长非递增子序列长度 +#n=int(input()) +#height=tuple(map(int,input().split())) +def intercept_missiles(height,n): + dp=[1]*(n+1) #dp[i]表示第i个位置索引的导弹是可拦截的最后一个导弹 + for i in range(n): + for j in range(i): #时间复杂度为O(N^2) + if height[i]<=height[j]: #只有后者高度小于前者才需要判断 + dp[i]=max(dp[j]+1,dp[i]) + #此时,前面第j个位置dp[j]已能反映出它之前可拦截的导弹数 + return max(dp[i] for i in range(n)) + +#print(intercept_missiles(height)) + +''' +24375 小木棍 +''' + +''' +23997 奇数划分 +''' + +#回溯-递归解法 +ans=[] +def backtrack(start,remain,path): + if remain==0: + ans.append(path.copy()) + return + for i in range(start,remain+1,2): + if i>remain: + break + else: + path.append(i) + backtrack(i+2,remain-i,path) + path.pop() + +#n=int(input()) +#backtrack(1,n,[]) +#for i in ans: +# print(" ".join(map(str,i))) +#print(len(ans)) + +#动态规划算法 +#可以视作0-1背包问题的变种,不过从values最大值变成和为给定值 +#dp[i][j]表示前i个奇数是可以选择用或不用的,j是要凑出来的数值 + +def dp_backtrack(n): + odds=[i for i in range(1,n+1) if i%2==1] + m=len(odds) + dp=[[0]*(n+1) for _ in range(m+1)] + dp[0][0]=1 + for k in range(1,m+1): + j=odds[k-1] + for i in range(n+1): + dp[k][i]=dp[k-1][i] #如果不用当前第k个奇数 + if i>=j: #当前判定的奇数比需要表示的值更大,此时i-j>0,才有讨论用i的可能, + #否则我们在凑j时是不可能用i的 + dp[k][i]+=dp[k-1][i-j] + return dp[m][n] + +#n=int(input()) +#print(dp_backtrack(n)) + +''' +25815 回文字符串 +这里注意区分,如果只有增删两种操作,相当于最长回文子序列(LPS) +如果有增删改三种,显然改的效率大于增删,应该正向考虑这个问题 +''' +#类比最长公子序列 +def lps(str): + n=len(str) + if n==0: + return 0 + else: + dp=[[0]*(n) for _ in range(n)] + #dp[i][i]表示str[i……j]之间的最长回文子序列长度 + for i in range(n-1,-1,-1): + for j in range(i+1,n): + if str[i]==str[j]: + dp[i][j]=dp[i+1][j-1] + else: + dp[i][j]=min(1+dp[i+1][j],1+dp[i][j-1],1+dp[i+1][j-1]) + return dp[0][n-1] + +str=input().strip() +print(lps(str)) + + + + diff --git a/cheatsheet/cheatsheet/cheatsheet_search&sorting.py b/cheatsheet/cheatsheet/cheatsheet_search&sorting.py new file mode 100644 index 00000000..f49e0304 --- /dev/null +++ b/cheatsheet/cheatsheet/cheatsheet_search&sorting.py @@ -0,0 +1,521 @@ +''' +基础知识 +''' +#谢尔排序 +def shellSort(nums): + gap = len(nums) // 2 + while gap>0: + for i in range(gap,len(nums)): + temp=nums[i] + j=i + while j>=gap and nums[j-gap]>=temp: #类似于插入排序 + nums[j]=nums[j-gap] + j-=gap + nums[j]=temp + gap//=2 + return nums + +#快速排序 +def partition(nums, left, right): + pivot = nums[left] # 步骤1:选择最左侧元素作为基准 + i, j = left + 1, right # 步骤2:初始化指针(i从left+1开始) + + while True: + # 步骤3:从左找>pivot的元素 + while i <= j and nums[i] <= pivot: + i += 1 + + # 步骤4:从右找= pivot: + j -= 1 + + # 步骤5:检查指针位置 + if i > j: + break # 指针交叉,分区结束 + + # 步骤6:交换错位元素 + nums[i], nums[j] = nums[j], nums[i] + + # 步骤7:将基准放到正确位置 + nums[left], nums[j] = nums[j], nums[left] + return j # 返回基准位置 + + +def quickSorting(nums, left, right): + # 递归终止条件:子数组长度<=1 + if left >= right: + return + + # 分区操作并获取基准位置 + pivot_index = partition(nums, left, right) + + # 递归排序左子数组(基准左侧) + quickSorting(nums, left, pivot_index - 1) + + # 递归排序右子数组(基准右侧) + quickSorting(nums, pivot_index + 1, right) + + +#归并排序(分治+拉链排序) +def mergeSort(nums): + if len(nums)<=1: + return nums + left=nums[:len(nums)//2] + right=nums[len(nums)//2:] + mergeSort(left) + mergeSort(right) + i,j=0,0 + nums.clear() #避免再建一个列表导致浪费更多空间&递归过程的nums不一样 + while itarget: + return None + else: + return None + + +#二分查找的while函数双指针表示法 + +n,k=map(int,input().split()) +woods=[] +for _ in range(n): + woods.append(int(input())) +max=sum(woods)//k + +if max==0: + print(0) + exit(0) +#如此可以找到满足题意的最大值 +low,high=1,max #这里代表的范围应该是闭区间 +while low<=high: #注意判定条件,break的条件是 low>high + mid=(low+high)//2 + tps=0 + for wood in woods: + tps+=wood//mid + if tps=k: #这一步同时也为了找到满足题意的最大值 + low=mid+1 +print(high) + + +#二分查找的列表表示法 +def binarySearch(nums,target): + i,j=0,len(nums)-1 + found=False + while i<=j and not found: + mid=(i+j)//2 + if nums[mid]==target: + found=True + return mid + elif nums[mid]>target: + return binarySearch(nums[:mid],target) + else: + return binarySearch(nums[mid+1:],target) + +#二分查找的经典运用场景:最小值最大化&最大值最小化 + +''' +实战题目 +''' +#切木材(去年机考题)(二分查找) +def binary_search(low,high): + tps=0 + mid=(low+high)//2 + if low==high: + return mid + for wood in woods: + tps+=wood//mid + if tps>k: + return binary_search(mid+1,high) + elif tps=right[j]: + new_nums.append(right[j]) + j+=1 + new_nums.extend(left[i:] if im: #一定错误的情况,要修改边界值将原low规避掉 + low=mid+1 + +print(low) + +#7613 白细胞计数 +''' +n=int(input()) +sample=[] +for i in range(n): + sample.append(float(input())) +sample.sort() +average=sum(sample[1:-1])/(n-2) +max=max(sample[-2]-average,average-sample[1]) +print("{:.2f}".format(average),"{:.2f}".format(max)) +''' + + +#7745 整数奇偶排序 +''' +nums=list(map(int,input().split())) +odd=[] +even=[] +for i in nums: + odd.append(i) if i%2==1 else even.append(i) +odd.sort(reverse=True) +even.sort() +if odd: + print(" ".join(str(x) for x in odd)+" "+" ".join(str(x) for x in even)) +else: + print(" ".join(str(x) for x in even)) +''' + +#8207 和为给定数 +''' +n=int(input()) +nums=list(map(int,input().split())) +target=int(input()) + +nums1=[num for num in nums if num<=target] +nums1.sort() + +left,right=0,len(nums1)-1 +found=False + +while leftlimit: + return False + if sum+arr[i]<=limit: + sum+=arr[i] + else: + count+=1 + sum=arr[i] + if count<=m: + return True + else: + return False + + result=Max + + while Min<=Max: + Mid=Min+(Max-Min)//2 + if is_feasible(arr,m,Mid): + result=min(result,Mid) + Max=Mid-1 + else: + Min=Mid+1 + return result + +''' +n,m=map(int,input().split()) +arr=[] +for i in range(n): + arr.append(int(input())) +Min=max(arr) +Max=sum(arr) + +print(fajo(arr,m,Min,Max)) +''' + +#5472 求逆序对数 +def merge(arr,left,mid,right): + i=left + j=mid+1 + temp=[] + count=0 + while i<= mid and j <=right: + if arr[i]<=arr[j]: + temp.append(arr[i]) + i+=1 + else: + temp.append(arr[j]) + count+=(mid-i+1) + j+=1 + for k in range(len(temp)): + arr[left+k]=temp[k] + return count + +def merge_sort(arr,left,right): + if left>=right: + return 0 + mid=(left+right)//2 + count=merge_sort(arr,left,mid)+merge_sort(arr,mid+1,right) + count+=merge(arr,left,mid,right) + return count + +def bubble_sort(arr): + n = len(arr) + swap_count = 0 + for i in range(n): + for j in range(0, n-i-1): + if arr[j] > arr[j+1]: + arr[j], arr[j+1] = arr[j+1], arr[j] + swap_count += 1 + return swap_count + + +#9201 Freda越野跑(逆序对数) +#n=int(input()) +#arr=list(map(int,input().split())) +#ans=0 + +def merge_sort(arr): + global ans + if len(arr)==1: + return arr + k=len(arr)//2 + a=merge_sort(arr[:k]) + b=merge_sort(arr[k:]) + a.append(-1) + b.append(-1) + inda,indb=0,0 + for i in range(len(arr)): + if a[inda]=len(matrix) or j<0 or j>=len(matrix[0]) or matrix[i][j]!="1": + return + matrix[i][j]=island_num + dfs(matrix,i+1,j,island_num) + dfs(matrix,i-1,j,island_num) + dfs(matrix,i,j+1,island_num) + dfs(matrix,i,j-1,island_num) + +def bfs(matrix,island_num): + directions=[(0,1),(0,-1),(-1,0),(1,0)] + queue=deque() + for i in range(len(matrix)): + for j in range(len(matrix[0])): + if matrix[i][j]==island_num: + queue.append((i,j,0)) + while queue: + x,y,steps=queue.popleft() + for dx,dy in directions: + newx,newy=x+dx,y+dy + if 0<=newx=right + +l,r=0,R +while lnums[j+1]: #内循环,与自己相邻的元素对比 + nums[j],nums[j+1]=nums[j+1],nums[j] + flag=True + if not flag: + break + return nums +''' +插入排序 +原理:数组左侧是已排好序的子数组,子数组右侧是要排序的元素base,从右往左地与左侧元素比较 + 如果更小,左侧元素索引右移;否则放在这个位置 +评价:最差时间复杂度O(N^2),最佳时间复杂度O(N),对应输入数组完全有序时 + 自适应排序、原地排序、稳定排序 + 在数据量较小时,插入排序比快速排序更快 +''' +def insertion_sort(nums): + for i in range(1,len(nums)): + base=nums[i] + j=i-1 + while j>=0 and nums[j]>base: + nums[j+1]=nums[j] + j-=1 + nums[j+1]=base + return nums diff --git a/cheatsheet/cheatsheet/cheatsheet_tree.py b/cheatsheet/cheatsheet/cheatsheet_tree.py new file mode 100644 index 00000000..9a6d1a8d --- /dev/null +++ b/cheatsheet/cheatsheet/cheatsheet_tree.py @@ -0,0 +1,678 @@ +''' +利用 python 自带的 heapq 库建堆 +''' +import heapq +heap=[] +num=int(input()) +heapq.heappush(heap,num) #将新元素插入堆 +heapq.heappop(heap) #弹出堆顶 +heapq.heapify(heap) #建堆操作 +#针对一个列表建堆,依据列表中某一位置的元素排序 +#可以模拟lambda表达式的结构 +a1=1 +a2=2 +a3=3 +arr=[a1,a2,a3] +arr_heap=(a2,arr) +heapq.heappush(heap,arr_heap)#默认按照元组的第一个元素排序 + +''' +利用边的信息(node,left=-1,right=-1)建树 +利用字典node_dist储存结点与key的关系,方便地返回对应值的结点 +''' +#二叉树的操作(去年机考题) +class TreeNode: + def __init__(self,key,left=None,right=None,parent=None): + self.key=key + self.left=None + self.right=None + self.parent=None + +t=int(input()) +for _ in range(t): + #建树 + n,m=map(int,input().split()) + node_dict={} + for _ in range(n): + x,y,z=map(int,input().split()) + if x not in node_dict: + node_dict[x]=TreeNode(x) + node=node_dict[x] + if y!=-1: + if y not in node_dict: + node_dict[y]=TreeNode(y) + l_node=node_dict[y] + node.left=l_node + l_node.parent=node + if z!=-1: + if z not in node_dict: + node_dict[z]=TreeNode(z) + r_node=node_dict[z] + node.right = r_node + r_node.parent = node + for x,x_node in node_dict.items(): + x_node.key=x + +''' +利用文本信息建树 +本题的启示:1. 通过设置self.children_count检验下一个数据放在左子树还是右子树 + 2. 通过设置last_node来储存某一层最后一个处理的结点,方便构建树 +''' +#文本二叉树(去年机考题) +#读入数据 +class NodeTree(): + def __init__(self,key): + self.key=key + self.left=None + self.right=None + self.parent=None + self.child_count=0 + +n = int(input()) +for _ in range(n): + # 读入数据 + node_dict={} + nodes=[] + last_node=[False]*100 #储存的是树结点 + + #建树 + while True: + a=list(input()) + if a==["0"]: + break + nodes.append(a) + for key in nodes: + if len(key)==1: + root=key[0] + node_dict[key[0]]=NodeTree(key[0]) + last_node[0]=node_dict[key[0]] + else: + depth=len(key)-1 + parent=last_node[depth-1] + if key[-1]=="*": + parent.child_count=1 + else: + new_node=key[-1] + node_dict[new_node]=NodeTree(new_node) + last_node[depth]=node_dict[new_node] + if parent.child_count==0: + parent.left=node_dict[new_node] + parent.child_count += 1 + elif parent.child_count==1: + parent.right=node_dict[new_node] + for key,node in node_dict.items(): + node.key=key + +''' +深度优先搜索:前序中序与后序遍历 +此处给出一例题:由前序、中序遍历生成后序遍历 +''' +#重建二叉树(作业题) +def rebuild(pre,mid): + if not pre and not mid: + return "" + root=pre[0] + mid_index=mid.index(root) + pre_left=pre[1:mid_index+1] + pre_right=pre[mid_index+1:] + mid_left=mid[:mid_index] + mid_right=mid[mid_index+1:] + return rebuild(pre_left,mid_left)+rebuild(pre_right,mid_right)+root + +def preorder(node): + if not node: + return "" + else: + return node.key + preorder(node.left) + preorder(node.right) + +#中序遍历 +def inorder(node): + if not node: + return "" + else: + return inorder(node.left)+node.key+inorder(node.right) + +#后序遍历 +def postorder(node): + if not node: + return "" + else: + return postorder(node.left) + postorder(node.right)+node.key + +''' +二叉搜索树 +建树过程展示如下: +''' +class TreeNode: + def __init__(self,val,left=None,right=None,parent=None): + self.val=val + self.left=left + self.right=right + self.parent=parent + +class BinarySearchTree: + TreeNode=TreeNode + def __init__(self): + self.root=None + self.size=0 + def put(self,val=0): + self.root=self._put(val,self.root) + def _put(self,val,curr): + if curr is None: + return TreeNode(val) + elif valcurr.val: + curr.right=self._put(val,curr.right) + else: + curr.val=val + return curr + +tree=BinarySearchTree() +nums=[41,467,334,500,169,724,478,358,962,436] +for num in nums: + tree.put(num) + +''' +二叉树的最近公共祖先查询(LCA问题) +''' +q=int(input()) +for _ in range(q): + a,b=map(int,input().split()) + na,nb=node_dict[a],node_dict[b] + while True: + if na.depth>nb.depth: #保证a的层数一定比b少 + na,nb=nb,na + while na.depth左子树->右子树 + res.append(root.val) + pre_order(root.left) + pre_order(root.right) + +def in_order(root): + if root is None: + return + #访问优先级:左子树->根节点->右子树 + in_order(root.left) + res.append(root.val) + in_order(root.right) + +def post_order(root): + if root is None: + return + #访问优先级:左子树->根节点->右子树 + post_order(root.left) + post_order(root.right) + res.append(root.val) + +res=[] +#时间复杂度分析:O(N) +#空间复杂度分析:最差情况下,树退化为链表,递归深度达到n,占用O(N)栈帧空间 + +''' +Chapter 7.3 二叉树数组表示 +可以根据层序遍历将所有节点存储在一个数组中 +对于完全二叉树,设父节点索引为i,则左子节点索引为2i+1,右子节点索引为2i+2 +对于非完全二叉树,这种索引失效,可以在数组中显式地表达所有的None +优点: +连续内存空间,缓存友好;完全二叉树节省空间;允许随机访问节点 +缺点: +不适合存储数据量过大、None过多的树;插入与删除的效率较低 +''' +class ArrayBinaryTree: + def __init__(self,arr:list[int|None]): + self._tree=list(arr) + + def size(self): #列表长度 + return len(self._tree) + + def val(self,i): + if i<0 or i>=self.size(): + return None + return self._tree[i] + + def left(self,i): #获得第i个节点的左子节点索引 + if i<0 or 2*i+1>=self.size(): + return None + return 2*i+1 + + def right(self,i): + if i<0 or 2*i+2>self.size(): + return None + return 2*i+2 + + def parent(self,i): + if i<0 or i>self.size(): + return None + return (i-1)//2 + + def level_order(self): #层序遍历 + self.res=[] + for i in range(self.size()): + if not self.val: + self.res.append(self.val(i)) + return self.res + +''' +从全括号表达式建立表达式解析树 +''' +def buildParseTree(fpexp): + fplist=fpexp.split() + pStack=[] + currentTree=eTree=TreeNode("") + pStack.append(currentTree) + for i in fplist: + if i=="(": + currentTree.insertLeft(" ") + pStack.append(currentTree) + currentTree=currentTree.getLeftChild(" ") + elif i in ["+","-","*","/"]: + currentTree.setRootVal(i) + currentTree.insertRight("") + pStack.append(currentTree) + currentTree=currentTree.getRightChild(" ") + elif i==")": + currentTree=pStack.pop() + elif ord("0")<=ord(i)<=ord("9"): + currentTree.setRootVal(int(i)) + currentTree = pStack.pop() + else: + raise ValueError + return eTree + +import operator +def postorderval(tree): + opers={"+":operator.add,"-":operator.sub,"*":operator.mul,"/":operator.truediv} + if tree: + left=postorderval(tree.left) + right=postorderval(tree.right) + if left and right: + return opers[tree.getRootVal()](left,right) + else: + return tree.getRootVal() + else: + return None + + +''' +作业题 +''' +#1790 二叉树 +nums=[] +#while True: + # test=list(map(int,input().split())) + # if test==[0,0]: + # break + #nums.append(test) + + +def left(m): + return 2*m +def right(m): + return 2*m+1 +def node(m,n): + if m>n: + return 0 + elif m==n: + return 1 + else: + return node(left(m),n)+node(right(m),n)+1 + + +# 这样递归可能导致栈溢出,且时间复杂度较高O(NlogN) +def count_subtree_nodes(m,n): + if m==0: + return 0 + sum_nodes=0 + level=0 + while True: + start=m*(2**level) + if start>n: + break + end=start+(2**level-1) + if end<=n: + sum_nodes+=2**level + else: + sum_nodes+=n-start+1 + level+=1 + return sum_nodes + +#for _ in nums: +# print(count_subtree_nodes(_[0],_[1])) + + +#1257 重建二叉树 +def rebuild(pre,mid): + if not pre and not mid: + return "" + root=pre[0] + index=mid.index(root) + lmid=mid[:index] + rmid=mid[index+1:] + lpre=pre[1:index+1] + rpre=pre[index+1:] + return rebuild(lpre,lmid)+rebuild(rpre,rmid)+root + +#while True: + # try: + # a, b = input().split() + # print(rebuild(a,b)) + #except EOFError: + # break + +#5431 二叉搜索树 +''' +class TreeNode: + def __init__(self,val,left=None,right=None,parent=None): + self.val=val + self.left=left + self.right=right + self.parent=parent + +class BinarySearchTree: + TreeNode=TreeNode + def __init__(self): + self.root=None + self.size=0 + def put(self,val=0): + self.root=self._put(val,self.root) + def _put(self,val,curr): + if curr is None: + return TreeNode(val) + elif valcurr.val: + curr.right=self._put(val,curr.right) + else: + curr.val=val + return curr + +nums=list(map(int,input().split())) +tree=BinarySearchTree() +for i in nums: + tree.put(i) + +def preorder(root,ans): + if root is None: + return + ans.append(root.val) + preorder(root.left,ans) + preorder(root.right,ans) + +ans=[] +preorder(tree.root,ans) +print(" ".join(map(str,ans))) +''' + +#6947 树的转换 +class GNode: + def __init__(self): + self.children=[] +def build_general_tree(sequence): + root=GNode() + stack=[root] + for char in sequence: + if char=="d": + new_node=GNode() + root.children.append(new_node) + stack.append(new_node) + elif char=="u": + stack.pop() + return root +def calc_general_height(node): + if not node.children: + return 0 + return max(calc_general_height(child) for child in node.children)+1 + +class BNode: + def __init__(self): + self.left=None + self.right=None +def convert_to_binary(g_node): + if not g_node: + return None + b_node=BNode() + if g_node.children: + b_node.left=convert_to_binary(g_node.children[0]) + current=b_node.left + for child in g_node.children[1:]: + current.right=convert_to_binary(child) + current=current.right + return b_node +def calc_binary_height(b_node): + if b_node is None: + return -1 + left_height=calc_binary_height(b_node.left) + right_height=calc_binary_height(b_node.right) + return max(left_height,right_height)+1 + +''' +if __name__=="__main__": + sequence=input().strip() + + general_root=build_general_tree(sequence) + h1=calc_general_height(general_root) + binary_root=convert_to_binary(general_root) + h2=calc_binary_height(binary_root) + + print(f"{h1}=>{h2}") +''' + +#14863 合并果子 +''' +import heapq +n=int(input()) +nums=list(map(int,input().split())) +if n==1: + print(0) +else: + ans=0 + heap=[] + for i in nums: + heapq.heappush(heap,i) + + while len(heap)>1: + a=heapq.heappop(heap) + b=heapq.heappop(heap) + s=a+b + ans+=s + heapq.heappush(heap,s) + + print(ans) +''' + + +#24686 树的重量 +import sys +def main(): + input=sys.stdin.read().split() + ptr=0 + k,n=int(input[ptr]),int(input[ptr+1]) + ptr+=2 + + size=(1<end: + return + if start<=l and r<=end: + lazy[node]+=delta + return + mid=(l+r)//2 + push_down(node,r-l+1) + update_range(2*node,l,mid,start,end,delta) + update_range(2*node+1,mid+1,r,start,end,delta) + weight[node]=weight[2*node]+weight[2*node+1]+lazy[2*node]*(mid-l+1)\ + +weight[2*node+1]*(r-mid) + def query_range(node,l,r,start,end): + if rend: + return 0 + if start<=l and r<=end: + return weight[node]+lazy[node]*(r-l+1) + push_down(node,r-l+1) + mid=(l+r)//2 + left_sum=query_range(2*node,l,mid,start,end) + right_sum=query_range(2*node+1,mid+1,r,start,end) + return left_sum+right_sum + + for _ in range(n): + parts=input[ptr] + if parts=="1": + x=int(input[ptr+1]) + y=int(input[ptr+2]) + ptr+=3 + level=0 + tmp=x + while tmp<=size: + level+=1 + tmp=2*tmp + subtree_size=(1<<(k-(x.bit_length()-1)))-1 + start=x + end=x+subtree_size-1 + update_range(1,1,size,start,end,y) + else: + x=int(input[ptr+1]) + ptr+=2 + level=0 + tmp=x + while tmp<=size: + level+=1 + tmp=2*tmp + subtree_size=(1<<(k-(x.bit_length()-1)))-1 + start=x + end=x+subtree_size-1 + res=query_range(1,1,size,start,end) + print(res) + +#if __name__=="__main__": +# main() + + +#24682 简单树上最近公共祖先查询(LCA问题) +#24637 宝藏二叉树 +class TreeNode: + def __init__(self,value,left=None,right=None): + self.value=value + self.left=left + self.right=right +n=int(input()) +lsts=list(map(int,input().strip().split())) +nodes=[TreeNode(i) for i in lsts] +for i in range(n): + if 2*i+1k: + return binary_search(mid+1,high) + elif tps=right[j]: + new_nums.append(right[j]) + j+=1 + new_nums.extend(left[i:] if i=85: + high=mid + +print(low) +''' + +#8209 月度开销(二分查找) +''' +n,m=map(int,input().split()) +payment=[] +for _ in range(n): + payment.append(int(input())) + +def kaixiao(target): + count=1 + current_sum=0 + for i in payment: + if current_sum+i<=mid: + current_sum+=i + else: + count+=1 + current_sum=i + return count + + +low,high=max(payment),sum(payment) +while lowm: #一定错误的情况,要修改边界值将原low规避掉 + low=mid+1 + +print(low) + +''' + + + +#1818 红与黑(DFS) +''' +def dfs(x,y): + count=1 + row=len(mapp) + col=len(mapp[0]) + visited[y][x]=True + direction=[(0,1),(1,0),(0,-1),(-1,0)] + for dx,dy in direction: + new_x=x+dx + new_y=y+dy + if 0<=new_x<=col-1 and 0<=new_y<=row-1 and not visited[new_y][new_x] and mapp[new_y][new_x]==0: + count+=dfs(new_x,new_y) + return count + +while True: + n,m=map(int,input().split()) + if n==0 and m==0: + break + mapp=[[0 for _ in range(n)] for _ in range(m)] + current_x=current_y=0 + for i in range(m): + a=input() + a=list(str(a)) + for j in range(n): + if a[j]=="#": + mapp[i][j]=1 + elif a[j]==".": + mapp[i][j]=0 + else: + current_x = j + current_y = i + mapp[i][j] = 0 + + visited=[[False for _ in range(n)]for _ in range(m)] + visited[current_y][current_x]=True + print(dfs(current_x,current_y)) + +''' + +#无向图的深度优先搜索 +''' +n,m=map(int,input().split()) +edges=[[0 for _ in range(n)] for _ in range(n)] +for _ in range(m): + a,b=map(int,input().split()) + edges[a][b]=1 + edges[b][a]=1 +visited=[0 for _ in range(n)] +ans=[] +def dfs(i): + global ans + visited[i]=1 + ans.append(i) + for e in range(n): + if edges[i][e]==1 and visited[e]==0: + visited[e]=1 + dfs(e) +for i in range(n): + if visited[i]==0: + dfs(i) + + +print(" ".join(map(str,ans))) + +''' + +#23163 判断无向图是否联通有无回路 +''' +n,m=map(int,input().split()) +graph=[[] for _ in range(n)] +for _ in range(m): + a,b=map(int,input().split()) + graph[a].append(b) + graph[b].append(a) +visited=[0 for _ in range(n)] +want_visited=[1 for _ in range(n)] + +connected=True +loop=False +def dfs(i,parent): #回溯这一步不能算作构成环 + global loop + visited[i]=1 + for e in graph[i]: + if e==parent: + continue + elif visited[e]==1: + loop=True + else: + dfs(e,i) + +for i in range(n): + if visited[i]==0: + dfs(i,-1) + if visited!=want_visited: + connected=False + +print("connected:yes" if connected else "connected:no") + +print("loop:yes" if loop else "loop:no") + + +#2721 文本二叉树 +class NodeTree(): + def __init__(self,key): + self.key=key + self.left=None + self.right=None + self.parent=None + self.child_count=0 + +#前序遍历 +def preorder(node): + if not node: + return "" + else: + return node.key + preorder(node.left) + preorder(node.right) + +#中序遍历 +def inorder(node): + if not node: + return "" + else: + return inorder(node.left)+node.key+inorder(node.right) + +#后序遍历 +def postorder(node): + if not node: + return "" + else: + return postorder(node.left) + postorder(node.right)+node.key + +n=int(input()) +for _ in range(n): + #读入数据 + node_dict={} + nodes=[] + last_node=[False]*100 #储存的是树结点 + + #建树 + while True: + a=list(input()) + if a==["0"]: + break + nodes.append(a) + for key in nodes: + if len(key)==1: + root=key[0] + node_dict[key[0]]=NodeTree(key[0]) + last_node[0]=node_dict[key[0]] + else: + depth=len(key)-1 + parent=last_node[depth-1] + if key[-1]=="*": + parent.child_count=1 + else: + new_node=key[-1] + node_dict[new_node]=NodeTree(new_node) + last_node[depth]=node_dict[new_node] + if parent.child_count==0: + parent.left=node_dict[new_node] + parent.child_count += 1 + elif parent.child_count==1: + parent.right=node_dict[new_node] + for key,node in node_dict.items(): + node.key=key + print(preorder(node_dict[root])) + print(postorder(node_dict[root])) + print(inorder(node_dict[root])) + if _