今天講的數論和數據結構,上午講的內容,上課的老師認爲「友好」;
我。。
其實聽的還能夠,畢竟以前學過,exgcd和線性篩和exgcd求逆元;node
Exgcd()
是求解ax+by = gcd(a,b)的算法
Ax + by = m當且僅當m%gcd(a,b) == 0時有解
由於gcd(a,b) == gcd(b,a %b)
因此只要咱們找到bx2+(a%b)y2==gcd(b,a%b)
就能夠
A%b ==a – a/bb
因此bx2+(a%b)y2 ==ay2+b(x - a / b y)
當b==0時x=1是方程解,而後回溯算法
歐拉篩 for(int i=2; i<=n; i++){ if(!vis[i]) prime[cnt++]=i; for(int j = 0; j < cnt && i * prime[j] <= n; j++){ vis[i * prime[j]]=prime[j]; if(i % prime[j] == 0) break; //防止一個數不是被他的最小因子篩掉 //例如若是沒有這句,12會被i==4,j==2時篩掉,但實際上應該被i==6,j==1時篩掉 } }
歐拉篩不只能夠篩素數還能夠求最小質因子數組
逆元
若是AB % M = 1
那麼A、B互爲在模M下的逆元
若是A、M不互質,那麼A不存在模M下的逆元。
AB%M == AB+MY
--------------------------------------------網絡
Int mod_inverse(int a, int m){ Int x, y; Exgcd(a, m, x, y); Return (x % m + m) % m; }
可是後面的題目都是英文不說(老師翻譯了),還沒什麼思路,數據結構
下午講的數據結構多是老師預計的沒講完,講的二叉堆,二叉搜索樹,線段樹,樹狀數組優化
和幾道題目,相比數論仍是好不少的翻譯
下午的題目至少還聽懂了好幾道,可是隻實現出了一個,並且沒有oj評測和數據點,而後下午大部分時間在寫一道上古時代就應該會的題指針
迪傑斯特拉堆優化code
而後一直沒寫出來,最後理解了可是仍是不過,我吧我看的那篇題解代碼沾上去也不過。。。。。我一臉懵,我寫了這麼長時間怎麼不對。。。blog
用什
二維樹狀數組
•void add(int x,int y, int val) •{ • for(int i=x;i<=n;i+=lowbit(i)) • for(int j=y;j<=m;j+=lowbit(j)) • s[i][j]+=val; •}
都是加一維(以添加爲例)
並查集
路徑壓縮
Find(int x){return x == fa[x] ? x : f[x] = find(f[x])}
按秩合併 對於每一個並查集維護一個size數組,每次合併兩個數組時將小的合併到大的上
X = find(x);y = find(y); If(size[x] > size[y]) {fa[y] = x;size[x] += size[y]};//初始化時令每個size=1; Else{fa[x] = y;size[y] += size[x]};
只寫路徑壓縮複雜度就很低,很難被卡掉,不過卡常的時候能夠用按秩合併
關押罪犯
(作過,講過不知道多少遍的題......)
1.二分答案將<當前答案的邊連起來,判斷是否爲二分圖(黑白染色法)
//二分圖斷定
vector<int> e[N]; int col[N]; //col[u]表示u的顏色,1爲白色,-1爲黑色,0爲未染色 bool flag=true; //是否爲二分圖 void dfs(int u,int c) { col[u]=c; for(int i=0;i<e[u].size();++i) { int v=e[u][i]; if(!col[v]) dfs(v,-c); else if(col[v]==c) flag=false; } } for(int i=1;i<=n;++i) if(!col[i]) dfs(i,1);
by老師
2.從大到小排序邊(兩人的怒氣值),每次若是x和沒有敵人,就將x的敵人設成y,不然就將x和y的敵人放到同一個並查集,表明在同一個監獄,y和x操做相同
當咱們發現當前枚舉的邊關係的兩我的x,y已經在同一集合,咱們雖然有可能經過其餘方式使他們不在同一集合,但那樣會使其餘更大的邊連起來(由於咱們從大到小枚舉,枚舉當前邊以前其餘邊已經要求並查集就是這樣,因此咱們只能讓這件事發生,他們的影響力即爲答案)
星球大戰
因爲並查集不支持刪邊操做,可是並無強制在線
咱們能夠倒着加邊,即先求最後刪完邊,再加一條邊(倒數第二個刪的邊)
求倒數第二個狀況,以此類推
例8
一個無相連通圖,每條邊都有權值,兩個點互相到達的代價是他們通過路徑的最大權值
每次詢問
輸出全部互相到達代價小於k的兩個城市
離線處理,按k值從小到大排序,是一個加邊的過程,用並查集維護連通塊
Trie字典樹
用二維數組存ch[n][m]n表明最長串的長度,m表明每個串的每個字符有多少不一樣的狀況
例如:每個都是小寫字母組成的字符串m就是26
插入:
初始化
O = 0;
查看字符串中第i個字符有沒有在o的後面現過(即ch[o][第i點]是否不等於0)
,出現過就讓」指針」o = 當前節點的標號
沒有就新建一個點ch[o][當前點]=++cnt,o = cnt
`i++,重複以上操做
例9
給定n個數求出其中兩個數異或最大值
將全部的數補至30位(2進制)(爲了從最高位比較),而後放到踹樹裏(二進制)
每次選取一個數,在踹樹上匹配,由於咱們從最高位匹配,因此若是如今咱們能夠選擇0或1
(1)當前選擇1的話假設之後都是最壞狀況(即每次都只能選0)異或後答案是1後面全是0
(2)和當前選0的話之後都是最好狀況(即每次都能選1)大啊是0後面全是1
因此咱們看出當前選1的話不管如何都會優於選0,因此每次貪心選,(固然,若是沒有1只能選0),把n個數都[]跑完以後去max
例十
•維護一個數據結構,支持:
•1.插入一個正整數x(x<=10^9)
•2.詢問已插入的數中有多少個與y異或獲得的結果>=z(y,z<=10^9)
•操做數<=10^5
查詢的時候,好比說咱們要求結果大於10011,咱們當前若是走1這條路最差是1000000(比10011大),這棵樹就不須要遞歸了,直接加上這顆樹的大小(須要記一個size數組)
當前選0的話最好狀況是01111(小於10011),咱們也不須要遞歸,由於永遠得不到咱們想要的結果,直接忽略,這樣比暴力憂不少
例11
這個改題面爲查詢的時候p沒有限制
維護每一個點的前綴和,放到踹樹中,全部數的異或和爲sum,每次找與x^sum異或後的最大值,
由於a^a = 0,因此將sum和某一個前綴異或獲得的就是當前位置開始的後綴
St表
倍增的思想,解決的是,RMQ問題(即某一區間的最大或最小值)
F[i][j]表明從i開始的2的j次方個節點的最值
F[i][j] = max(f[i][j – 1],f[f[i][j - 1]+ 1][j - 1])
即第i個節點開始到第2的j次方後的節點的最值=max(i開始第2的j-1次方的最值,i開始第2的j – 1次方開始再2的j – 1次方的最值)
即,一個區間最值 = max(他左一半的最值,右一半的最值)
好比1到4的區間最值(f[1][2]) = 1到2最值(f[1][1])和3到4最值(f[3][1])中大的那個
LCA的三種解決方式
1倍增:
F[i][j]表明第i個節點向上第2的j次方後的節點
F[i][j] = f[f[i][j – 1]][j - 1]
即第i個節點向上第2的j次方後的節點=(第i個節點向上跳2的j – 1次方後的節點)再向上跳2的j – 1 次方的節點
由於2的j – 1次方加2的j – 1次方 = 2的j次方
2轉換RMQ問題
某個巨佬已經證實出RMQ和LCA能夠互相轉換.
(1)求出樹的dfs序
(2)兩個點u,v的LCA是pos[u]到pos[v]中深度最小的點
Ps:pos[x]表明x在dfs中個出現的順序,u表明較早出現的點,v和u相反
3用tarjan算法
然而我並不會tarjan...
•①記錄每一個點的詢問
•②dfs回溯時用並查集合並(將子結點集合併到父節點集合,以父節點爲根)
•③查詢lca(u,v)時假設此時u已訪問,v剛訪問到,那麼u的並查集的根即爲答案
強行復制,逃.
Hash
哈希容易出現哈希碰撞,可使用無錯哈希
開m個vector(m爲哈希的模數),每次遇到相同模數的時候將當前值放進去,每一個點的指望仍是O(1),因此對空間和時間影響不大
雙模哈希理論能夠被卡,可是很是困難,因此能夠用,若是被卡了就是臉黑木辦法hhh
即每個數模兩個不一樣的數,只有兩個模數都相同,才能證實出現過
哈希還能夠用來記錄狀態,好比八數碼問題使得判重只須要O(1)
圖論
克魯斯卡爾算法證實
N==1時,最小生成樹顯然
在n == k成立時,n == k + 1有一條邊(u,v)是鏈接新節點的最短邊,由於須要構成一顆樹,因此,這個點必定要連出一條邊,假設不是最短邊,咱們就將最短邊連起來,在一棵樹中連一條不重複的邊會構成環,那麼環中任意刪除一條邊仍是樹,因此,連上最短邊再刪除一條環中邊確定更優
例1
N個村莊,每一個村莊要麼打一口井,要麼從某一個有水的地方建一個管道,問最小代價
有水☞
(1)村莊建了井
(2)村莊向有水的地方建了一個管道
建另外一個節點0爲」水井」,他和每個節點連邊,邊權爲節點建水井的費用
這樣只要求最小生成樹便可
貨車運輸
方法一
克魯斯卡爾算法
用克魯斯卡爾算法求最大生成樹,
用倍增求LCA,順便求出路徑最小值
方法二
Kruskal重構樹
在kruskal的過程當中
若當前邊所連兩點u和v不在一個集合內
則新建一個節點node,點權爲該邊邊權
而後鏈接u所在集合的根與node以及v所在集合的根與node
重構完成以後,指定每一個集合的根做爲所在森林的根
則u到v路徑上最大邊權的最小值 就是LCA(u,v)的點權
強行復制,逃.
例3溫馨的路線
給定一張圖,n個點,m條邊,求一棵生成樹,知足它的邊權最小值最大。輸出這個最小值
直接用克魯斯卡爾求最大生成樹
另外一個方法 玄學 && 找」出阿寶」作法,二分答案
Spfa算法判負環,
我無論了.....弄了半天也沒搞懂原理,反正就是每一個點進隊n - 1次就說明有負環
也有dfs的作法,每次枚舉每個點,每次走負邊(1到2是-2,2到3是1也算負邊),若是一個點再次被搜到,就說明有負環
Tarjan算法
Dfn[n]表明點n第幾回搜到
low[n]表明n及n搜索樹子樹中的點中能訪問到的點dfn的最小值
本身寫個僞代碼
塔尖(int x){
標記爲x訪問過
For遍歷每一條邊(遞歸每一個子樹)
若是當前節點沒有訪問過
遞歸子樹根節點
Low[x]取x和子樹根最小值
不然
Low[x]和子樹根的low取min
}
若是dfs[n] == low[n]
記錄強連通份量個數的變量++
將棧中所有元素彈出,標記vis[元素] = n表明這些元素在這個強連通份量裏
間諜網絡
咱們已知的某些受賄的間諜,和他們須要的錢。咱們還知道哪些間諜手中具體掌握了哪些間諜的資料。假設總共有n個間諜(n不超過3000),每一個間諜分別用1到3000的整數來標識。
請根據這份資料,判斷咱們是否有可能控制所有的間諜,若是能夠,求出咱們須要支付的最少資金。不然,輸出不能被控制的一個間諜。
首先tarjan縮點(如下是有解的狀況),
對於沒有環的圖,咱們選擇入度爲零的人進行賄賂,其他有入度的人都會被揭發
對於有環的圖,咱們塔尖縮點,就變成了有向無環圖,這個點的代價就是須要最少錢被賄賂的那我的須要的錢
差分約束
差分約束系統由形如xi - xj <= k這樣的式子組合而成,
求xs - xt最大值
求解方法:
(1)將形式變成xi - xj <= k
(2)令xj向xi連一條長度爲k的邊
(3)求出s到t的最大值
圖中有負環則解不存在,沒法互相到達則答案爲無限大(由於沒有什麼限制他)
今天其實聽得不怎麼好,有不少東西沒有記下來
動態規劃
狀態與記憶化搜索
狀態其實就是問題的子問題
記憶化搜索 vs 動態規劃
無需考慮順序 須要考慮順序
容易實現,容易理解 不容易實現,不容易理解
常數大 常數小
優化困難 部分容易優化
線性動態規劃
小齊挖礦
如今有m + 1個星球,從左到右標號爲0到m,小奇最初在0號星球。
有n處礦體,第i處礦體有ai單位原礦,在第bi個星球
每次只能調到x + 4或x + 7的位置,問最多挖多少礦
經過%#$@^%@!能夠發現,兩個星球只要相隔距離大於17,就必定能到達
因此咱們把全部距離相隔大於17的星球距離設爲18,這樣就只須要18 * n的空間
以及只須要18 * n的時間
大搬家
如今有一個長度爲n的搬家指示,其中ai表示住在第i棟房子的人須要搬家到第ai棟房子
N家連續搬家,結果,第3次搬家結果跟第一次結果相同
問有多少種不一樣的數列答案對1000000007取模
最大子矩陣
有一個n*2的矩陣,請你選出其中k個子矩陣,使得這
個k個子矩陣分值之和最大。子矩陣不能互相重疊
狀態太多直接複製ppt上的吧
定義狀態
fi,j表示前i行,選了j個子矩陣,當前兩列不屬於任何矩陣的最大值。
gi,j表示前i行,選了j個子矩陣,當前兩列屬於同一個矩陣的最大值。
hi,j表示前i行,選了j個子矩陣,當前兩列屬於不一樣矩陣的最大值。
si,j表示前i行,選了j個子矩陣,左邊一列屬於一個矩陣的最大值。
ti,j表示前i行,選了j個子矩陣,右邊一列屬於一個矩陣的最大值.
玩具取名
名字是從」WING」四個字母中選出一個,而後通過一系列變化變成名字
區間dp,設f[i][j]][k]爲i 到j這個區間k能不能被合成
每次枚舉區間時,枚舉每個變化方案,看看可否由小的區間合併成這個區間
染色
長度爲n的木板每次課選擇一個連續的區間染色,後染的會覆蓋先染的
問最少染幾回
F[i][j] 表示i到j的區間染色的最小值
若是a[i] == a[i + 1] 那麼f[i][j] = f[i + 1][j]
若是a[j - 1] == a[j] 那麼f[i][j] = f[i][j - 1]
若是a[i] == a[j] 那麼 f[i][j] = f[i + 1][j],f[i][j - 1],f[i][j]
除了這些之外,f[i][j] = f[i][mid]+f[mid + 1][j]
以上式子都要取min
而後大多數題都沒記筆記,實際由於都不會,晚上剩下的時間作了一道區間dp,加深理解吧(這道題難度遠遠低於今天講的題目的難度)