日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

蓝桥杯之算法模板题 Python版

發布時間:2024/1/1 python 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 蓝桥杯之算法模板题 Python版 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

藍橋杯之算法模板題 Python版

文章目錄

  • 藍橋杯之算法模板題 Python版
    • 線段樹
    • DP 動態規劃
      • dp, LIS **
      • 01背包
      • 完全背包
      • 多重背包
      • 混合背包
      • 分組背包
    • 區間DP
      • 一.什么是區間dp?
        • 二.核心思路
      • 三.樸素區間dp(n^3)
    • 博弈論
      • nim博弈
        • 兩堆的情形
        • 一般情形
    • 變體 反nim博弈
    • 快速冪
      • 矩陣快速冪
    • 最短路徑問題
      • Floyd算法
      • Dijkstra算法
    • 差分
    • 計算幾何基礎
      • 兩線段相交
    • 并查集
      • 一般并查集
      • 種類并查集
    • 最小生成樹
    • 樹狀數組
    • 樹狀數組求逆序對
    • 威爾遜定理

記錄一下算法模板題,這樣方便查閱和學習,希望好好加油

線段樹

import os import sysN,Q = map(int,input().split()) arr = [0] arr.extend(list(map(int,input().split()))) def ls(p):return p<<1 # p//2 def rs(p):return p<<1|1 # p//2 + 1 tree = [0 for _ in range(N<<2)] # 一共有2n個節點 tag = [0 for _ in range(N<<2)] # lazy_tag標記def pushdown(p,pl,pr):if tag[p]!=0:mid = pl + pr >> 1addtag(ls(p),pl,mid,tag[p])addtag(rs(p),mid+1,pr,tag[p])tag[p] = 0# tree[p] = tree[lr(p)] + tree[rs(p)]def push_up(p):tree[p] = tree[ls(p)] + tree[rs(p)] # 搭建線段樹 節點的值是求和 def bulid(p,pl,pr):if pl == pr:# tree[p] = float('-inf')tree[p] = arr[pl]return mid = pl + pr>>1bulid(ls(p),pl,mid)bulid(rs(p),mid+1,pr)# tree[p] = tree[pl] + tree[pr]push_up(p)# 增加lazy_tag標記 def addtag(p,pl,pr,d):tag[p] += dtree[p] += d*(pr-pl+1)def query(p,pl,pr,L,R): # L,R是查詢區間# 當前節點在查詢區間內if L <= pl and pr <= R: return tree[p]pushdown(p,pl,pr) # 標記向下傳遞res = 0mid = pl + pr >>1if L <= mid:res+=query(ls(p),pl,mid,L,R) if R > mid:res+=query(rs(p),mid+1,pr,L,R)return res# 更新線段樹,也就是加上k L,R是更新區間 def update(p,pl,pr,L,R,d):if L<=pl and pr<=R:addtag(p,pl,pr,d)returnpushdown(p,pl,pr) # 標記向下傳遞mid = pl + pr >> 1if L <= mid: update(ls(p),pl,mid,L,R,d)if R > mid: update(rs(p),mid+1,pr,L,R,d)push_up(p)bulid(1,1,N) for _ in range(Q):q = list(map(int,input().split()))if q[0] == 1:update(1,1,N,q[1],q[2],q[3])elif q[0] == 2:print(query(1,1,N,q[1],q[2])) import os import sys def ls(p):return p<<1 def rs(p):return p<<1|1 def push_up(p):tree[p]=tree[rs(p)]+tree[ls(p)] def build(p,pl,pr):if pl==pr:tree[p]=1returnmid=(pl+pr)>>1build(ls(p),pl,mid)build(rs(p),mid+1,pr)push_up(p) def addtag(p,pl,pr,d):tag[p]=dtree[p]=d*(pr-pl+1) def push_down(p,pl,pr):if ~tag[p]!=0:mid=(pl+pr)>>1addtag(ls(p),pl,mid,tag[p])addtag(rs(p),mid+1,pr,tag[p])tag[p]=-1 # 把1變成0 def update0(p,pl,pr,cnt):if cnt==0:returnif tree[p]==cnt:addtag(p,pl,pr,0)returnmid=(pl+pr)>>1push_down(p,pl,pr)if tree[ls(p)]>cnt:update0(ls(p),pl,mid,cnt)else:cnt-=tree[ls(p)]addtag(ls(p),pl,mid,0)update0(rs(p),mid+1,pr,cnt)push_up(p) # 把0變成1 def update1(p,pl,pr,cnt):if cnt==0:returnif pr-pl+1-tree[p]==cnt:addtag(p,pl,pr,1)returnmid=(pl+pr)>>1push_down(p,pl,pr)if mid-pl+1-tree[ls(p)]>cnt:update1(ls(p),pl,mid,cnt)else:cnt-=(mid-pl+1-tree[ls(p)])addtag(ls(p),pl,mid,1)update1(rs(p),mid+1,pr,cnt)push_up(p) def query(p,pl,pr,L,R):if L<=pl and pr<=R:return tree[p]push_down(p,pl,pr)mid=(pl+pr)>>1res=0if L<=mid:res+=query(ls(p),pl,mid,L,R)if R>mid:res+=query(rs(p),mid+1,pr,L,R)return res n,m=map(int,input().split()) tree=[0 for _ in range(n<<2)] tag=[-1 for _ in range(n<<2)] build(1,1,n) for _ in range(m):op,num=map(int,input().split())if op==0:pos=n-tree[1]cnt=max(0,num-pos)update0(1,1,n,cnt)elif op==1:pos=tree[1]cnt=max(0,n-num+1-pos)update1(1,1,n,cnt) ans1,ans2=[],[] for i in range(1,n+1):if query(1,1,n,i,i)==0:ans1.append(i)else:ans2.append(i) for x in ans1[::-1]+ans2:print(x,end=' ')

DP 動態規劃

dp, LIS **

''' https://www.lanqiao.cn/problems/1188/learning/ 難度: 中等 標簽: dp, LIS '''import os import sys import bisect # 請在此輸入您的代碼n = int(input()) a = list(map(int,input().split()))dp = [float('inf')]*(n+1) dp[0] = a[0] for i in range(1,n):t = bisect.bisect_left(dp,a[i])dp[t] = a[i]print(bisect.bisect_left(dp,float('inf')))

01背包

動態轉移方程
f[i][j]=max(f[i?1][j],f[i?1][j?v]+w)(j>v)f[i][j] = max(f[i-1][j], f[i-1][j-v] + w)(j>v) f[i][j]=max(f[i?1][j],f[i?1][j?v]+w)(j>v)

# https://www.lanqiao.cn/problems/1174/learning/ # 難度: 簡單 標簽: dp, 背包, 01背包 import os import sys# 請在此輸入您的代碼 N,V = map(int,input().split()) # f[N][V] # f[i][j] 代表 i 件物品 , 容量為 j 的時候,得到最大的價值 f = [[0]*(V+1) for _ in range(N+1)]for i in range(1,N+1):# v為體積, w為價值v, w = map(int, input().split())for j in range(1,V+1):# 第i件物品有兩種選擇,# 第1種是選第i件物品,f[i-1][j]# 第2種是不選第i件物品,f[i-1][j]if j < v: f[i][j] = f[i-1][j]else:f[i][j] = max(f[i-1][j], f[i-1][j-v] + w)print(f[N][V])

完全背包

一般就是
f[i][j]=max(f[i?1][j?k?v]+w?k)(0<=k<j//v)f[i][j] = max(f[i-1][j-k*v] + w*k)(0<=k<j//v) f[i][j]=max(f[i?1][j?k?v]+w?k)(0<=k<j//v)
不過可以轉化為動態轉移方程
f[i][j]=max(f[i?1][j],f[i][j?v]+w)f[i][j] = max(f[i-1][j],f[i][j-v] + w) f[i][j]=max(f[i?1][j],f[i][j?v]+w)

''' https://www.lanqiao.cn/problems/1175/learning/ 難度: 簡單 標簽: DP, 背包, 完全背包 '''import os import sys# 請在此輸入您的代碼 N,V = map(int,input().split())# f[i][j]表示前i種,總體積不超過j,最大的總價值 f = [[0]*(V+1) for _ in range(N+1)]# 完全背包問題,可以買多個 for i in range(1,N+1):v,w = map(int,input().split())for j in range(1,V+1): # 這里是體積的范圍# t = j//v# f[i][j] = f[i-1][j]# for x in range(1,t+1): # x是第i件物品的數量# f[i][j] = max(f[i][j],f[i-1][j-x*v]+w*x)# 優化后寫法,已經把所有的也考慮進去了if j < v:f[i][j] = f[i-1][j] # 相當于不買第 i 件物品else:f[i][j] = max(f[i-1][j],f[i][j-v] + w) # 這里是比較買i件物品和不買i件物品 print(f[N][V])# 壓縮成一維 # dp = [0]*(V+1) # v,w = [],[] # for i in range(N): # v,w = map(int,input().split()) # for j in range(1,V+1): # if j >= v: # dp[j] = max(dp[j-v] + w, dp[j]) # print(dp[V])

多重背包

對于多重背包來說,實際上與一般是一樣的情形的構造,就是數量受限制了而已

不過多重背包也有一種二進制的壓縮寫法,復雜度就會更低一點

''' https://www.lanqiao.cn/problems/1176/learning/ 難度: 簡單 標簽: dp, 背包, 多重背包 ''' import os import sys# 請在此輸入您的代碼N,V = map(int,input().split())# 多重背包和完全背包是一樣的構造方式 f = [[0]*(V+1) for _ in range(N+1)] for i in range(1,N+1):v,w,s = map(int,input().split())for j in range(1,V+1):# 多重背包的區別就是,不可以直接簡化,因為數量已經有了限制,所以說獨立一個循環進行判斷和更新for k in range(s+1):if k*v <= j:# 這一部分判斷,是否買k個f[i][j] = max(f[i][j],f[i-1][j-k*v] + k*w)else:break print(f[N][V])

二進制寫法

多重背包二進制還可以進行優化,要不然上一部分的復雜度有 On的三次方

會把多重背包轉化為01背包,對于01背包就稍微簡單一點

比如200個數量的物體,可以轉為為1,2,4,8,…,64,74這么多組

因為1127的數可以由164構成,然后200-127 = 73

(1~127 都可以表示出來,選出任意一種與 73 組合就可以表示出 74 ~ 200 ,所以合起來就可以表示 1~200)。

相當于每個數量的為一組

# 多重背包二進制還可以進行優化,要不然上一部分的復雜度有 On的三次方 # 會把多重背包轉化為01背包,對于01背包就稍微簡單一點 # 比如200個數量的物體,可以轉為為1,2,4,8,....,64,74這么多組 # 因為1~127的數可以由1~64構成,然后200-127 = 73 # (1~127 都可以表示出來,選出任意一種與 73 組合就可以表示出 74 ~ 200 ,所以合起來就可以表示 1~200)。 # 相當于每個數量的為一組N,V = map(int,input().split()) v = [0]*12010 w = [0]*12010cnt = 0 for i in range(N):a,b,s = map(int,input().split())k = 1# 按照二進制的形式分組while k <= s:cnt += 1v[cnt] = k*aw[cnt] = k*bs = s - kk = k*2# 不能按照二進制分組的物體數量單獨劃分為一組。if k > 0:cnt += 1v[cnt] = a*sw[cnt] = b*s f = [0]*(cnt+1) # 分組后就等同于0 1 背包 for i in range(1,cnt + 1):for j in range(V,0,-1):if j >= v[i]:f[j] = max(f[j],f[j-v[i]] + w[i])else:breakprint(f[V])

混合背包

其中又有混合背包問題,混合背包問題就是,我們的數量變成無限了,對于無限來說,我們就不可以直接利用二進制進行計算。

不過我思考了一下,除非說以我們的體積作為我們的上界,還是可以進行的

首先就是先根據一個無限的情況進行一個判斷,這里是改完全背包的,因為這些都是變體

''' https://www.lanqiao.cn/problems/1177/learning/ 難度: 簡單 標簽: dp, 背包, 混合背包 '''N,V = map(int,input().split())# f[i][j]表示前i種,總體積不超過j,最大的總價值 f = [[0]*(V+1) for _ in range(N+1)]for i in range(1,N+1):v,w,s = map(int,input().split())for j in range(1,V+1):# 多重背包的區別就是,不可以直接簡化,因為數量已經有了限制,所以說獨立一個循環進行判斷和更新if s != 0:for k in range(s+1):if k*v <= j:# 這一部分判斷,是否買k個f[i][j] = max(f[i][j],f[i-1][j-k*v] + k*w)else:breakelse:k = 0while k*v <= j:f[i][j] = max(f[i][j],f[i-1][j-k*v] + k*w)k += 1 print(f[N][V])

如果s=0表示該商品有無限個,但實際背包不可能放入無限多個,在此假設最大個數為能夠全部放入背包的數量

所以這個也可以通過調整一個上界進行,因為我們的體積是有限的,所以也可以調整多重背包的二進制進行修改

''' https://www.lanqiao.cn/problems/1177/learning/ 難度: 簡單 標簽: dp, 背包, 混合背包 '''N,V = map(int,input().split()) v = [0]*12010 w = [0]*12010cnt = 0 for i in range(N):a,b,s = map(int,input().split())if s == 0:s = V//a # 設置上界即可k = 1# 按照二進制的形式分組while k <= s:cnt += 1v[cnt] = k*aw[cnt] = k*bs = s - kk = k*2# 不能按照二進制分組的物體數量單獨劃分為一組。if k > 0:cnt += 1v[cnt] = a*sw[cnt] = b*s f = [0]*(cnt+1) # 分組后就等同于0 1 背包 for i in range(1,cnt + 1):for j in range(V,0,-1):if j >= v[i]:f[j] = max(f[j],f[j-v[i]] + w[i])else:breakprint(f[V])

分組背包

其實就類似于01背包,對于一個物品有兩種決策選或不選,但是分組背包是在01背包的基礎上對物品進行了分組,并且每一組只能最多選擇一個物品,所以我們不妨用01背包的思想去思考分組背包.

分析:我們設f[i][j]為當前考慮到了第i組物品,剩余容里為j的背包能裝物品的最大價值,那么很容易想到我們需要去枚舉第i組物品,考慮選哪一個物品時最優的(或者不選),狀態轉移方程就是
if(j>=v[i][k])f[i][j]=max(f[i][j],f[i?1][j?v[i][k]]+w[i][k])i f ( j > = v [ i ] [ k ] ) f [ i ] [ j ] = m a x ( f [ i ] [ j ] , f [ i ? 1 ] [ j ? v [ i ] [ k ] ] + w [ i ] [ k ] ) if(j>=v[i][k])f[i][j]=max(f[i][j],f[i?1][j?v[i][k]]+w[i][k])
v[i][k]和w[i][k]分別表示第i組物品中第k個物品的體積和價值

for(int i=1;i<=n;i++)for(int j=0;j<=m;j++)for(int k=1;k<=s[i];k++)//s[i]表示第i組物品的個數if(j>=v[i][k])//剩余的背包容量j大于第i組的第k個物品的體積 {f[i][j] = max(f[i][j],f[i-1][j-v[i][k]]+w[i][k]);} ''' https://www.lanqiao.cn/problems/1178/learning/ 難度: 簡單 標簽: dp, 背包, 分組背包 '''N,V = map(int,input().split())f = [0]*(V+1) v = [[0]] w = [[0]] s = [0] for i in range(1,N+1):s.append(int(input()))# 一組物品只能買一件vi = [0]wi = [0]for _ in range(s[i]):a,b = map(int,input().split())vi.append(a)wi.append(b)v.append(vi)w.append(wi)# f[i][j] 代表在選擇i組中, 體積不超過j的最大價值 f = [[0]*(V+1) for _ in range(N+1)] for i in range(1,N+1): # 1~N 組數for j in range(V,-1,-1): # V~0 體積數for k in range(1,s[i]+1): # 1~i 分組的物品數if j >= v[i][k]:f[i][j] = max(f[i][j],f[i-1][j - v[i][k]] + w[i][k])print(f[N][V])

還可以進行壓縮成一維的,減少空間

for 所有的組kfor v=V..0for 所有的i屬于組kf[v]=max{f[v],f[v-c[i]]+w[i]} # 壓縮成一維 N,V = map(int,input().split())f = [0]*(V+1) v = [[0]] w = [[0]] s = [0] for i in range(1,N+1):s.append(int(input()))# 一組物品只能買一件vi = [0]wi = [0]for _ in range(s[i]):a,b = map(int,input().split())vi.append(a)wi.append(b)v.append(vi)w.append(wi)# f[i][j] 代表在選擇i組中, 體積不超過j的最大價值 f = [0]*(V+1) for i in range(1,N+1): # 1~N 組數for j in range(V,-1,-1): # V~0 體積數for k in range(1,s[i]+1): # 1~i 分組的物品數if j >= v[i][k]:f[j] = max(f[j],f[j - v[i][k]] + w[i][k])print(f[V])

區間DP

一.什么是區間dp?

? 顧名思義:區間dp就是在區間上進行動態規劃,求解一段區間上的最優解。主要是通過合并小區間的 最優解進而得出整個大區間上最優解的dp算法。

二.核心思路

? 既然讓我求解在一個區間上的最優解,那么我把這個區間分割成一個個小區間,求解每個小區間的最優解,再合并小區間得到大區間即可。所以在代碼實現上,我可以枚舉區間長度len為每次分割成的小區間長度(由短到長不斷合并),內層枚舉該長度下可以的起點,自然終點也就明了了。然后在這個起點終點之間枚舉分割點,求解這段小區間在某個分割點下的最優解。板子如下:

for(int len = 1;len<=n;len++){//枚舉長度for(int j = 1;j+len<=n+1;j++){//枚舉起點,ends<=nint ends = j+len - 1;for(int i = j;i<ends;i++){//枚舉分割點,更新小區間最優解dp[j][ends] = min(dp[j][ends],dp[j][i]+dp[i+1][ends]+something);}}}

三.樸素區間dp(n^3)

轉移方程

dp[j][ends] = min(dp[j][ends],dp[j][i]+dp[i+1][ends]+weigth[i][ends]);

j~ends堆合并 = 較小的(原來, 分割點i坐部分重量 + 分割點i右邊部分重量 + 合并后兩堆總重量)

注:可以用sum[j] - sum[i - 1]表示i~j堆的重量!

博弈論

nim博弈

這實際上是一個尼姆博弈的問題,尼姆博弈就是一個兩人博弈,2名玩家輪流從數堆物品中拿取一定數量的物品,每次拿取時先選擇某一堆,再從中拿取任意數量個物品,至少拿1個,至多將這一堆物品全部拿走,不能不拿。拿到最后一個物品的玩家獲勝。

尼姆博弈是一個兩人博弈,2名玩家輪流從數堆物品中拿取一定數量的物品,每次拿取時先選擇某一堆,再從中拿取任意數量個物品,至少拿1個,至多將這一堆物品全部拿走,不能不拿。拿到最后一個物品的玩家獲勝。

兩堆的情形

我們從最簡單的兩堆物品的情形開始分析,并使用二元組(n,m)來表示這兩堆物品當前的數量。當(n,m)情形下先手方\后手方有必勝策略時,我們稱(n,m)為制勝位置。

我們將說明:當n=m時,后手有必勝策略,否則先手有必勝策略。

  • 當n=m=1時,先手方僅能夠將其中一堆完全取走,故后手方只需要將另一堆的1個物品取走即可獲勝。即(1,1)是后手方的制勝位置。
  • 當n=m=k>1時,無論先手方選擇哪一堆,取走多少數量的物品,后手方只需要選擇另一堆,并取走相同數量的物品,就可以將物品堆的狀態從(k,k)轉換到(j,j),其中j<k。如此操作下去,由于兩堆物品的數量保持相等且嚴格遞減,故后手方玩家總能將物品堆的數量轉換為(1,1)或(0,0)。由上面的討論與游戲規則知,后手方必勝。即(n,m),n=m是后手方的制勝位置。
  • 當時,先手方只需要從較多的一堆物品中拿取適量的物品,使得兩物品堆物品數量一致,就將情形轉換為了上述兩種情況之一,且自身處于后手方。由上面的討論知,先手方必勝。即(n,m),是先手方的制勝位置。

定義:物品堆的尼姆和是一個二進制數,它是由所有物品堆中物品的數量轉換為二進制后,進行異或運算得到的。設有k個物品堆,分別有

一般情形

一般情形下的必勝策略與兩堆的情形基本一致:若物品堆的尼姆和為0,則后手方有必勝策略,否則先手方有必勝策略。必勝策略的構造基于下面的定理:

  • 在尼姆和為0時,無論如何拿取物品,拿取之后物品堆的尼姆和一定不為0;
  • 在尼姆和不為0時,總存在一種拿取物品的方式,使得拿取之后物品堆的尼姆和為0。
  • 我們先說明必勝策略的構造方式

    • 若物品堆的尼姆和為0,則無論先手方如何拿取,操作之后物品堆的尼姆和一定不為0,先手方總是不能將物品拿完。后手方總是可以選擇拿取方式使得物品堆的尼姆和再次為0,同時物品的數量嚴格減小,這樣操作下去,有限多輪之后即可使得后手方拿取物品后所有物品均被拿取,即后手方有必勝策略。
    • 若物品堆的尼姆和不為0,則先手方總可以選擇拿取方式使得拿取之后物品堆的尼姆和為0,且處于后手方的位置。由上述討論可知,先手方有必勝策略。
    ''' https://www.lanqiao.cn/problems/1218/learning/ 難度: 簡單 標簽: nim博弈 '''import os import syst = int(input()) for _ in range(t):n = int(input())ans = 0a = list(map(int, input().split()))for i in range(n):ans ^= a[i]if ans!=0:print('NO')else:print('YES')

    變體 反nim博弈

    如果將規則改為拿到最后一個物品者敗,可得到尼姆博弈的一種變體。此時我們有下面的結論:

  • 若尼姆和為0且所有堆中僅有1個物品,則先手方有必勝策略;
  • 若尼姆和不為0且至少有一堆物品數量大于1,則先手方有必勝策略;
  • 否則后手方有必勝策略。
  • 具體策略分析如下:

    A. 假定尼姆和為0且所有堆中僅有1個物品,那么一定有偶數堆物品,否則尼姆和不為0。實際上此時雙方均沒有選擇,只能每次拿走一堆物品,最終先手方拿走倒數第二堆物品,迫使后手方拿走最后一堆物品,輸掉博弈。故先手方必勝。

    經過相似的分析我們可以得出,若所有堆中僅有1個物品,且共有奇數堆物品,那么后手方必勝。

    B. 假定尼姆和不為0且至少有一堆物品數量大于1,此時分為兩種情況討論:

    B.1 只有一堆物品的數量大于1:

    B.1.1此時若共有偶數個物品堆,則先手方只需要將物品數量大于1的這一堆全部拿走,就將情況轉換為A中所有堆中僅有1個物品,且共有奇數堆物品并處于后手方;

    B.1.2此時若共有奇數個物品堆,則先手方只需要使得物品數量大于1的這一堆物品拿取之后只剩1個物品,就將情況轉換為A中所有堆中僅有1個物品,且共有奇數堆物品并處于后手方;

    綜合以上兩點,此時先手方必勝。

    B.2 至少有2堆物品的數量大于1:

    此時先手方只需要將尼姆和變為0即可,由上面的討論我們知道這樣的拿取方式一定是存在的。并且拿完之后一定還至少有2堆物品的數量大于1,這是因為假設拿完之后只有第i堆物品數量大于1,不妨設其二進制表示的中最左側的1在2d這一位上,那么物品堆的尼姆和中2d這一位上一定是1,因為只有的二進制表示中這一位是1,其他物品堆數量的二進制表示這一位上都是0,而

    ,從而尼姆和不為0,但這與尼姆和為0矛盾。故拿完之后一定還至少有2堆物品的數量大于1。由于物品數量嚴格減少,如此操作下去,在有限輪之后一定會遇到B.1中的情形,從而先手方必勝。

    所以就是兩種情況先手必勝,除此之外都是后手必勝

  • 石子個數全部為111 && sum==0sum == 0sum==0

  • 至少有一堆石子個數大于111 && sum≠0sum \neq 0sum?=0

  • """ https://www.lanqiao.cn/problems/1219/learning/ 難度: 簡單 標簽: 反nim博弈 """t = int(input())for _ in range(t):n = int(input())a = list(map(int,input().split()))flag = Trueans = 0cnt = 0for x in a:if x > 1:flag = Falseans = ans^xif flag:if ans == 0:print('NO') # ans = 0,nim和為0,也就說明是偶數,這時候先手必勝else:print('YES')else:if ans != 0: # 至少有一堆>1,并且nim不為0,先手勝print('NO')else:print('YES')

    快速冪

    ''' https://www.lanqiao.cn/problems/1181/learning/ 難度: 簡單 標簽: 快速冪 '''import os import sys# 請在此輸入您的代碼def quickpow(n,m,p):res = 1while m:if m & 1:res = (res * n)%pn = (n*n)%pm = m>>1return rest = int(input()) for i in range(t):n, m, p = map(int,input().split())print(quickpow(n,m,p))

    矩陣快速冪

    ''' https://www.lanqiao.cn/problems/1180/learning/ 難度: 簡單 標簽: 矩陣快速冪 '''# 請在此輸入您的代碼def multi(X,Y):n,m,k = len(X),len(X[0]),len(Y[0])res =[[0]*k for _ in range(n)]for i in range(n):for j in range(k):ans = 0for x in range(m):ans += X[i][x]*Y[x][j]res[i][j] = ansreturn resdef fastpow(X,m):res = [[1, 0], [0, 1]]while m:if m&1:res = multi(res,X)X = multi(X,X)m = m>>1return rest = int(input()) q = [[1,1],[1,0]] for _ in range(t):n = int(input())res = fastpow(q,n-1)res = res[0][0]print(res)

    最短路徑問題

    Floyd算法

    ''' https://www.lanqiao.cn/problems/1121/learning/ 難度: 簡單 標簽: Floyd '''n,m,q = map(int,input().split())MAP = [[float('inf')]*(n+1) for _ in range(n+1)] for i in range(m):u,v,w = map(int,input().split())MAP[u][v] = wdef floyd(MAP):for k in range(1,n+1):for i in range(1,n+1):for j in range(1,n+1):if MAP[i][j] > MAP[i][k] + MAP[k][j]:MAP[i][j] = MAP[i][k] + MAP[k][j]floyd(MAP) for _ in range(q):st,ed = map(int,input().split())res = MAP[st][ed]if res != float('inf'):print(res)else:print(-1) ''' https://www.lanqiao.cn/problems/1122/learning/ 難度: 簡單 標簽: Dijkstra '''# floyd算法 n,m = map(int,input().split()) p = [[float('inf')]*(n+1) for _ in range(n+1)] for _ in range(m):u,v,w = map(int,input().split())p[u][v] = wdef floyd():for k in range(1,n+1):for i in range(1,n+1):for j in range(1,n+1):if p[i][j] > p[i][k] + p[k][j]:p[i][j] = p[i][k] + p[k][j]print('0',end = ' ')for i in range(2,n+1):if p[1][i] != float('inf'):print(p[1][i],end = ' ')else:print(-1,end = ' ')

    Dijkstra算法

    ''' https://www.lanqiao.cn/problems/1122/learning/ 難度: 簡單 標簽: Dijkstra '''import os import sys import functoolsn,m = map(int,input().split()) INF = float('inf') graph = [[INF] * (n) for _ in range(n)] for _ in range(m):u,v,w = map(int,input().split())graph[u-1][v-1] = w def djs(start):visited = [0]*ndist = [INF]*ndist[start - 1] = 0for i in range(n):# 找到未標記最近的點x = -1for y,u in enumerate(visited):if not u and (x == -1 or dist[x] > dist[y]):x = yvisited[x] = 1for y,w in enumerate(graph[x]):dist[y] = min(dist[y],dist[x] + w)print(" ".join(map(str,dist)))djs(1)

    差分

    # https://www.lanqiao.cn/problems/1276/learning/ # 難度: 簡單 標簽: 差分n,q = map(int,input().split()) a = [0]+list(map(int,input().split()))b = [0]*(n+2) for i in range(1,n+1):b[i] = a[i] - a[i-1]for i in range(q):l,r,x = map(int,input().split())b[l] += xb[r+1] -= xfor i in range(1,n+1):a[i] = b[i] + a[i-1]if a[i] <= 0:print(0,end =' ')else:print(a[i],end = ' ')

    計算幾何基礎

    兩線段相交

    ''' https://www.lanqiao.cn/problems/1287/learning/ 難度: 簡單 標簽: 計算幾何基礎 '''import os import sys# 請在此輸入您的代碼 #Python3.6 class point(): #定義類def __init__(self,x,y):self.x=xself.y=y def cross(p1,p2,p3):#跨立實驗x1=p2.x-p1.xy1=p2.y-p1.yx2=p3.x-p1.xy2=p3.y-p1.yreturn x1*y2-x2*y1 def IsIntersec(p1,p2,p3,p4): #判斷兩線段是否相交#快速排斥,以l1、l2為對角線的矩形必相交,否則兩線段不相交if(max(p1.x,p2.x)>=min(p3.x,p4.x) #矩形1最右端大于矩形2最左端and max(p3.x,p4.x)>=min(p1.x,p2.x) #矩形2最右端大于矩形最左端and max(p1.y,p2.y)>=min(p3.y,p4.y) #矩形1最高端大于矩形最低端and max(p3.y,p4.y)>=min(p1.y,p2.y)): #矩形2最高端大于矩形最低端#若通過快速排斥則進行跨立實驗if(cross(p1,p2,p3)*cross(p1,p2,p4)<0and cross(p3,p4,p1)*cross(p3,p4,p2)<0):D=2elif (cross(p1,p2,p3)*cross(p1,p2,p4)==0and cross(p3,p4,p1)*cross(p3,p4,p2)==0):D=1else:D=0else:D=0return Dt=int(input()) for i in range(t):p1,p2,p3,p4=point(0,0),point(0,0),point(0,0),point(0,0)x=list(map(float,input().split()))y=list(map(float,input().split()))p1.x,p1.y=x[0],x[1]p2.x,p2.y=x[2],x[3]p3.x,p3.y=y[0],y[1]p4.x,p4.y=y[2],y[3]print(IsIntersec(p1,p2,p3,p4))

    并查集

    一般并查集

    朋友的朋友是朋友

    ''' https://www.lanqiao.cn/problems/1135/learning/ 難度: 簡單 標簽: 并查集 '''N,M = map(int,input().split()) f = [i for i in range(N+1)] def find(x):if f[x] != x:f[x] = find(f[x])return f[x]def union(x,y):fx = find(x)fy = find(y)if fx != fy:f[fy] = fxfor i in range(M):op,x,y = map(int,input().split())if op == 2:if find(f[x]) == find(f[y]):print('YES')else:print('NO')elif op == 1:union(x,y)

    種類并查集

    一般的并查集是親戚的親戚是親戚

    一般的并查集,維護的是具有連通性、傳遞性的關系,例如親戚的親戚是親戚。但是,有時候,我們要維護另一種關系:敵人的敵人是朋友。種類并查集就是為了解決這個問題而誕生的。

    我們開一個兩倍大小的并查集。例如,假如我們要維護4個元素的并查集,我們改為開8個單位的空間:

    我們用14維護**朋友**關系(就這道題而言,是指關在同一個監獄的獄友),用58維護敵人關系(這道題里是指關在不同監獄的仇人)。現在假如我們得到信息:1和2是敵人,應該怎么辦?

    我們merge(1, 2+n), merge(1+n, 2);。這里n就等于4,但我寫成n這樣更清晰。對于1個編號為i的元素,i+n是它的敵人。所以這里的意思就是:1是2的敵人,2是1的敵人。

    現在假如我們又知道2和4是敵人,我們merge(2, 4+n), merge(2+n, 4);:

    發現了嗎,敵人的敵人就是朋友,2和4是敵人,2和1也是敵人,所以這里,1和4通過2+n這個元素間接地連接起來了。這就是種類并查集工作的原理。

    ''' https://www.lanqiao.cn/problems/1136/learning/ 難度: 簡單 標簽: 種類并查集 '''import os import sys# 請在此輸入您的代碼 n,m = map(int,input().split())# 用一半來維護朋友關系,另一半用來維護敵人關系 # 對于1個編號為i的元素,i+n是它的敵人。 f = [i for i in range(2*n+1)] # 種類并查集 def find(x):if f[x] != x:f[x] = find(f[x])return f[x]def union(x,y):fx = find(x)fy = find(y)if fx != fy:f[fy] = fxfor _ in range(m):x,y = map(int,input().split())# 判斷是否是朋友,或者相互是敵人,這樣就說明有問題if find(x) == find(y) or find(x+n) == find(y+n):print(x)breakunion(x,y+n) # 維護敵人關系union(x+n,y) # 維護敵人關系

    最小生成樹

    Kruskal算法,選擇邊,類似于并查集的寫法

    ''' https://www.lanqiao.cn/problems/1124/learning/ 難度: 簡單 標簽: Kruskal, Prim '''n,m = map(int,input().split()) # graph = [[0]*(n+1) for _ in range(n+1)] edge = [] for _ in range(m):u,v,w = map(int,input().split())edge.append((u,v,w))f = [i for i in range(n+1)]def find(x):if f[x] != x:f[x] = find(f[x])return f[x]def union(x,y):fx,fy = find(x),find(y)if fx != fy:f[fy] = fxans = 0 cnt = 0 edge.sort(key=lambda x:x[2]) for i in edge:u,v,w = iif find(u) != find(v) and cnt <= n - 1:ans += wunion(u,v)cnt += 1 if cnt < n - 1:print(-1) else:print(ans)

    樹狀數組

    def lowbit(x):return x & -xdef upate(x, d):while x <= n:tree[x] += dx += lowbit(x)def getsum(x):ans = 0while x:ans += tree[x]x -= lowbit(x)return ans

    樹狀數組求逆序對

    import os import sys# 請在此輸入您的代碼def lowbit(x):return x&-xdef update(x,d):while x <= n:tree[x] += dx += lowbit(x)def getsum(x):res = 0while x:res += tree[x]x -= lowbit(x)return resn = int(input()) tree = [0]*(n+1)a = list(map(int,input().split())) a = [0] + a ans = 0 tree = [0 for _ in range(n+1)] for i in range(1,n+1):update(a[i],1)ans += (i-getsum(a[i])) print(ans)

    威爾遜定理

    十八世紀中葉,一位英國法官約翰·威爾遜爵士,發現了數論中一種極為罕見的關系:取從1到某個質數所有連續正整數的乘積,例如從1乘到11,即11的階乘11!。顯然,11!能被從1到11的所有整數整除,除去11這個數,得10!。無疑10!不能被11整除。

    然而,如果給10!加上1的話,1×2×3×4×5×6×7×8×9×10+1=3628801,怎么也不會想到,3628801卻能被11整除(3628801÷11=329891)。類似地,從1到質數7的階乘7!中略去7,再加上1,得1×2×3×4×5×6+1=721,721也能被7整除(721÷7=103)
    11 和 7 都是質數,研究發現,此種整除性對一切質數都成立,但對合數卻不成立。下面的表格展示了這一規律:

    n

    (n-1)!

    (n-1)!+1

    [(n-1)!+1] mod n

    數性

    2

    1

    2

    0

    質數

    3

    2

    3

    0

    質數

    4

    6

    7

    3

    合數

    5

    24

    25

    0

    質數

    6

    120

    121

    1

    合數

    7

    720

    721

    0

    質數

    8

    5040

    5041

    1

    合數

    9

    40320

    40321

    1

    合數

    10

    362880

    362881

    1

    合數

    11

    3628800

    3628801

    0

    質數

    12

    39916800

    39916801

    1

    合數

    13

    479001600

    479001601

    0

    質數

    14

    6227020800

    6227020801

    1

    合數

    15

    87178291200

    87178291201

    1

    合數

    威爾遜定理:

    p 為質數時, (p-1)!+1 能被 p 整除。

    威爾遜定理逆定理:

    若一個數 (p-1)!+1 能被 p 整除,那么 p 為質數

    """ https://www.lanqiao.cn/problems/1244/learning/ 難度: 簡單 標簽: 威爾遜定理 題目寫錯了,求的是(n-1)%n的結果 """n = int(input())flag = False for i in range(2,int(n**0.5)+1):if n%i == 0:flag = Truebreakif not flag:print(n-1) else:if n == 4:print(2)else:print(0)

    總結

    以上是生活随笔為你收集整理的蓝桥杯之算法模板题 Python版的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。