多是圖論專題吧html
1.Tarjan縮點後是一張拓撲圖算法
2.標號的倒序是這張拓撲圖一個合法的拓撲序數組
1.是點雙而不是邊雙的只有兩點一線bash
2.邊雙縮點後是一棵樹網絡
3.一個點可能再多個點雙中,因而咱們求點雙的時候須要在兒子處進行統計low[v] >= dfn[u]數據結構
昨天打比賽而後今天頹廢去了ide
因此仍是圖論函數
爭取完結圖論?(不可能的。。學習
這個沒啥好說的\(f[i][j]\)表示從\(i\)到\(j\)的最短路,要先枚舉中介點\(k\),順序不能錯優化
由於這其實是個三維的滾動數組
複雜度\(O(n^3)\)
1.不能處理帶負權的邊
優化後是\(O((n + m)\log n)\)
就是SPFA複雜度的上界吧,仍是SPFA好寫,過了
複雜度\(O(nm)\)
會玄學A*能夠水過不少題啊
有一個論文算法,關於可持久化平衡樹維護最短路樹的
6.19 upd
若是咱們有一些限制形如\(x_{a} - x_{b} <= d\)
那麼咱們能夠把它聯繫到最短路上,若是\(b \rightarrow a\)有一條長度爲\(d\)的邊,那麼必然有\(x_{a} <= x_{b} + d\)
這樣咱們求最短路,能夠獲得\(x_{a}\)的最大值
爲何是小於等於號倒是最大值呢,由於咱們是從正無窮向下規約的
6.19 upd end
複雜度\(O(n^{2})\),能夠相似dij的優化可是優化以後不如kruskal
複雜度\(O(E \log E)\)
kruskal的正確性能夠在不少思惟題求最小生成樹中做爲優化邊數的一種方法
6.16upd:
|最大匹配數|=|最小頂點覆蓋|
最小頂點覆蓋的意思是咱們選擇個數最少的點而後覆蓋全部的邊
咱們考慮每一條邊必定連着一個被匹配的點,若是一條邊連着一個未匹配的點,那麼這條邊也必定連着一條被匹配的點,不然匹配能夠增長
|最大獨立集|+|最小頂點覆蓋|=頂點個數
最大獨立集就是選出一些點,這些點之間沒有邊相連
咱們把最小頂點覆蓋去除了,那麼剩下的頂點就沒有邊了啊
|最大匹配|+|最小邊覆蓋|=頂點個數
咱們往最大匹配中加邊,就能夠覆蓋全部頂點了,因此這個式子告訴咱們,最小邊覆蓋就是選擇最大匹配的那些邊,而後加入新的邊將未匹配點連接起來
6.16 upd end
複雜度\(O(n^3)\)
複雜度\(O(n^3)\)但常數很是小,適合夢想選手
四種連邊
那麼選了A必須選B',選了B必須選A'
A->B' B->A'
那麼選了A'必須選B,選了B'必須選A
A'->B B'->A
那麼選了A'必須選B',選了B'必須選A',選了A必須選B,選了B必須選A
A'->B' B'->A' A->B B->A
A’->A
選了A'必須選A,保證了A拓撲序在前
解的多解依賴於拓撲序的多狀況,這樣的話去除了A'在A前面的狀況
今天寫樹
Tarjan縮點便可
具體題目具體分析了
會出的題通常都是討論環上的如何操做
常常按照太重心和不太重心兩種方式考慮
多叉樹轉二叉樹,即左兒子右兄弟
實質很是暴力,就是在加入葉子的時候,走到重心的路徑,若遇到一棵樹大小超過必定比例的父親子樹的大小(設置一個分數,如0.7),則重構之
我怎麼會這麼個玩意
\(dp[i][S]\)表示特殊點的點集爲\(S\),根爲\(i\)的最小代價
而後轉移有兩種,一種是以同一個點爲根
\(dp[i][S] = min(dp[i][T] + dp[i][S \oplus T],dp[i][S])\)
一種是從另外一個根換過來
\(dp[i][S] = min(dp[j][S] + w[i][j],dp[i][S])\)
前面是子集枚舉,後面是暴力SPFA
學弟和小詹去廣州集訓了,zxg去六盤水支教了,全機房就剩我一我的了,感受有點玄妙
今天寫網絡流
ISAP和Dinic的本質都是分層圖跑暴力
ISAP
Dinic
都要注意sumE = 1,使得邊的標號從2開始
最大權閉合子圖
即選擇一個點集,保證這些點集連向的全部點都在這個點集裏
方法是源點向全部權值爲正的點連一條邊,容量爲權值,權值爲負的點向匯點連一條邊,容量爲權值的負數
若是問選擇什麼點集就直接在殘餘網絡中搜走到的點就好了
6.19 upd
有些狀況下好比每一個點有兩種選擇,每種選擇有不一樣的價值,則能夠轉化爲最小割問題
源點往i流一條容量爲代價1的邊,i往匯點流一條容量爲代價2的邊,中間可能還會有一些限制之類的,每一個點代價1和代價2的總和減去網絡流就是答案,由於較小的那種方案會被割掉
6.19 upd end
一種是暴力跑SPFA增廣(已經能夠糊弄過不少張圖了,況且貌似沒有複雜度下限同樣優秀的了)
一種是zkw費用流
這個算法常數比較小,每次至少選了一條邊進入可增廣的範圍
每條邊有一個上界up和下界low
和無源匯的上下界可行流同樣,不過能夠加上從匯點到源點容量爲正無窮的邊,從超級源和超級匯跑一遍可行流
而後再從給定的源匯跑一遍最大流
突然發現ISAP67ms,Dinic3000ms,不知道發生了什麼
和無源匯的上下界同樣,要先跑一邊無源匯的上下界可行流,把能知足的都先跑滿,而後再加上從匯點到源點的一條邊,繼續跑無源匯的上下邊可行流,若合法,最後答案就是這條邊反向邊的權值
這道題ISap由於循環流會被卡。。。
不知道寫點啥。。。
通常是給出一個序列,把序列分紅\(\sqrt{n}\)塊,每塊大小爲$\sqrt{n} $
而後考慮塊間合併和塊內處理,通常要求合併和塊內都是\(O(1)\),而後最多遍歷\(\sqrt{n}\)個塊,代價是\(O(\sqrt{n})\)
\(O(n\sqrt{n}\log n)\)適合夢想選手(誤
一道著名的分塊題是求區間衆數,作法是對於每個塊求前i個塊j個數的前綴和
而後再處理出以每一個塊爲開頭的塊衆數是什麼,這一步是\(O(n\sqrt {n})\)的,即從每一個塊開始把日後全部的數往以個桶裏扔
這樣我扔兩邊的那些零碎的時候,就能夠即時更新區間衆數了
即將左端點分塊,按塊排序,右端點從小到大排序
對於一個塊內右端點移動次數是\(O(n\sqrt{n})\),而左端點移動次數每次至多\(\sqrt{n}\),總移動次數也是\(O(n\sqrt{n})\)
塊的大小爲\(n^{2 / 3}\)共有\(n ^{1 / 3}\)塊
左右端點都按塊排序,時間維從小到大排序
那麼時間軸的移動,對於兩個不一樣的塊,移動次數是\(O(n)\),因此時間維移動了\(O(n^{5 / 3})\)
對於左端點的移動,每次在塊內最可能是\(O(n^{2/3})\)一共\(O(n)\)次詢問因此是\(O(n^{5/3})\)
右端點的移動,右端點只在塊裏是\(O(n^{5/3})\),左端點改變後右端點移動是\(O(n)\)的,可是不超過\(O(n^{4/3})\)
首先分塊變成了給樹分塊,方法就是用一個棧,若是遍歷一個兒子後棧中元素增長的量超過了我要分的塊,注意要先把兒子能分的塊分完了,再把父親扔進去
而後我移動兩個指針就是
先把\(u,v\)的lca取反
將\(u\)移動到目標節點\(tu\),而後把\(lca(u,tu)\)不動
\(v\)同理
而後將\(tu,tv\)的\(lca\)取反
忘了說,這是一件要堅持二十四天的事情,數字比較吉利
天天寫一點,看看能寫到哪吧。。
有點不想在學校待着,只有我一我的……
就是考慮能不能分紅左右兩個子問題,把合併控制在\(O(n)\)或者\(O(n \log n)\)級別
例如,求平面最近點對
咱們把平面分爲兩部分使得每一部分點數相等
而後咱們能夠用兩邊計算的最小值做爲中間合併時最小距離的限制
實際上這樣限制下來對於左邊的一個點,右邊可能對答案有貢獻的點不超過6個
CDQ分治主要解決的是三維偏序問題
首先咱們按照某一維排序
咱們在每一層計算左邊對右邊的貢獻,即用在每一層按照另外一維排序,而且將最後一維用數據結構維護,對於合法左邊的點把貢獻加給右邊
三維是\(O(n \log^{2} n)\)的,拓展到更高維度也是能夠的,可是沒有暴力好,例如著名的五維偏序就是bitset。。。
都帶個分字,我也就一塊兒說了
這個東西其實沒什麼好說的,就是對於一個單峯(谷)函數,分紅三段,左右兩端點各走\(1/3\),看哪一個值比較小(大),那麼就裏峯頂(谷底)更近一些,而不至於走過頭
有些函數能夠說一下,例如絕對值函數取最大值(斜率相同)是比較常見的三分函數
\(x + \frac{1}{x}\)有名的對勾函數也能夠考慮一下
。。。。單調函數二分
固然也有些奇怪的應用,不必定是函數,而是一個集合至少擴增到哪一個位置合法,是個隱蔽的單調函數
若是我選了\(k\)個數,求平均值最大,設平均值爲\(g\)的話,那麼能夠獲得
\[ \frac{\sum_{i = 1}^{k}v_{i}}{k} = g \]
若是咱們二分一個平均值看合不合法呢???
若是
\[ \frac{\sum_{i = 1}^{k}v_{i}}{k} \geq g \]
咱們只要把\(k\)移過去能夠獲得
\[ \sum_{i = 1}^{k}v_{i} \geq kg \]
而這個\(k\)實際上是咱們選擇的數的個數
那麼呢咱們再考慮一個轉化
\[ \sum_{i = 1}^{k}v_{i} - g \geq 0 \]
這樣的話,咱們只要選一個數就減一下\(g\),若是能獲得\(\geq 0\)的值證實這個平均值合法
6.16upd:有些時候須要大於0
計算幾何(我瘋了我爲啥要開這個。。。)
\(x_{1}y_2 - x_{2}y_{1}\)
獲得的是兩個向量的有向面積,逆時針正順時針負
\(x_{1}y_{1} + x_{2}y_{2}\)
獲得的是\(|a||b|cos<a,b>\)
struct Point { db x,y; Point(db _x = 0.0,db _y = 0.0) { x = _x;y = _y; } friend Point operator + (const Point &a,const Point &b) { return Point(a.x + b.x,a.y + b.y); } friend Point operator - (const Point &a,const Point &b) { return Point(a.x - b.x,a.y - b.y); } friend db operator * (const Point &a,const Point &b) { return a.x * b.y - a.y * b.x; } friend db dot(const Point &a,const Point &b) { return a.x * b.x + a.y * b.y; } friend Point operator * (const Point &a,db d) { return Point(a.x * d,a.y * d); } db norm() { return sqrt(x * x + y * y); } }P[MAXN];
friend bool InSegment(const Line &s,const Point &b) { db d = (b - s.a) * (s.b - s.a); if(!dcmp(d,0.0)) return false; return dot(s.a - b,s.b - b) <= 0; }
一條直線能夠用兩個點表示
friend Point GetInsect(const Line &s,const Line &t) { db S1 = (t.a - t.b) * (s.a - t.b); db S2 = (t.b - t.a) * (s.b - t.a); return s.a + (s.b - s.a) * (S1 / (S1 + S2)); }
對於線段相交只須要判這個點在不在這個線段上就行了
作一條平行於x軸或y軸的射線,若交點爲奇數則在內,偶數則不在內
選擇左下角的點,最下的同時最左或最左的同時最下,這個點必定在凸包上,而後把其他點按照極角排序,極角同樣的長度大的在後面
而後只須要用一個棧,看看新加入的這個點加進去後凸包是否是凸的
通常就是若是枚舉點逆時針移動,最優答案也逆時針移動,這就是旋轉卡殼了
每條直線按照平面內的幅角排序
Gter是若是\(a > b + eps\)返回真
for(int i = 1 ; i <= tot ; ++i) { while(ql < qr) { if(Gter(0.0,(S[i].b - S[i].a) * (p[qr - 1] - S[i].a))) --qr; else break; } while(ql < qr) { if(Gter(0.0,(S[i].b - S[i].a) * (p[ql] - S[i].a))) ++ql; else break; } q[++qr] = S[i]; if(ql < qr) { if(dcmp(q[qr].d,q[qr - 1].d)) { if(Gter((q[qr].b - q[qr].a) * (q[qr - 1].a - q[qr].a),0.0)) --qr; else q[qr - 1] = q[qr],--qr; } } if(ql < qr) p[qr - 1] = Cross_Point(q[qr],q[qr - 1]); } while(ql < qr) { if(Gter(0.0,(q[ql].b - q[ql].a) * (p[qr - 1] - q[ql].a))) --qr; else break; } p[qr] = Cross_Point(q[qr],q[ql]);
把凸包每一個點以左下角爲起點按極角排序,看看在哪兩個點之間,而後往兩邊二分便可
具體實現很麻煩,題PKUWCD2T3出過,可是題目到如今都沒公佈
給cy寫過一個凸包切點的流程,如今粘到這裏吧
我字怎麼那麼醜,爲何,枯了。
要不要開數據結構呢。。。
先不開,等下週複習吧(咕咕咕
今天是各類類型的動態規劃
衆所周知,動態規劃只須要腦子就夠了
其實是狀壓加hash壓縮輪廓線
看看能不能分割成子樹中的問題
一般有一類dp須要在狀態中加入假定的將來狀態,如JLOI / SHOI2016偵查守衛
還有線段樹合併等優秀方法
這個會的話就很簡單
看不出來的例如十二省聯考的皮配(像我)只能墊底了。。
一般是\(n^{3}\)的,可能會使用bitset
通常是\(f[i][k]\)和\(f[k + 1][j]\)與\(f[i][j]\)的合併
一般都會加入一維\([0/1]\)表示判斷是否和給定的上界相同,若是有下界一般會轉化乘\(F(R) - F(L - 1)\)的前綴和容斥形式,也有把上下界是否相等一塊兒壓進狀態裏的
我喜歡相似Floyd那樣的更新,也就是\(a\rightarrow b\) 乘上\(b \rightarrow c\),能夠更新\(a \rightarrow c\)
不只僅是線性齊次遞推式能夠更新,+和取max也是能夠更新的
\(a\rightarrow c = max(a\rightarrow c,a\rightarrow b + b\rightarrow c)\)
而且也知足結合律
\(f(x) = min_{i = 1}^{x - 1} \{f(i) + w[i,x]\}\)
知足對於\(x < y\),最優的決策點\(k(x) < k(y)\)
這裏有一點要注意的!
就是若是對於\(x\),\(i\)是最優的,那麼不表明\(i + 1\)轉移到\(y\)比\(i\)轉移到\(y\)更優
由於有多是,優 很是差 最優
那麼算法的流程實際上是這樣的,咱們一開始只有\(f(0)\)因而這些就設成
000000000000000
而後咱們計算出\(f(1)\)
會更改成
001111111111111
獲得2能夠改成
001111112222222
就是記錄每一個連續段,獲得一個數二分這個數能夠從哪一個位置開始更新,若是能夠覆蓋掉整個連續段就跳過
\(f(x) = min_{k = b[x]}^{x - 1}\{g(k)\} + w[x]\)
容易發現咱們要作的就是區間取最小值
單調隊列很容易能夠實現這一點
$f(x) = min_{i = 1}^{x - 1} {a[x]f(i) + b[x]g(i)} $
因爲是二元組,咱們把它畫在平面直角座標系上
設\(f(i) = x\),\(g(i) = y\),\(f(x) = P\)
P = ax + by
\(y = -\frac{a}{b}x + \frac{1}{b} P\)
很容易發現就是一條斜率固定的直線,從負無窮上移,第一個碰到的點就是答案
咱們只要維護一個下凸殼就能夠作到了
若斜率有單調變化,咱們能夠用第二種形式作到單調隊列優化
若是沒有則二分凸包
衆所周知sjq是個頹廢的女孩子
因此她昨天頹廢去了,今天(6.16)打算補兩天
這個你們耳熟能詳就是推不出來卷積式子
具體細節有點贅餘(畢竟是複習),因此直接上個板子好了
for(int i = 1,j = L >> 1; i < L - 1 ; ++i) { if(i < j) swap(p[i],p[j]); int k = L >> 1; while(j >= k) { j -= k; k >>= 1; } j += k; } for(int h = 2 ; h <= L ; h <<= 1) { int wn = W[(MAXL + on * MAXL / h) % MAXL]; for(int k = 0 ; k < L ; k += h) { int w = 1; for(int j = k ; j < k + h / 2 ; ++j) { int u = p[j],t = mul(w,p[j + h / 2]); p[j] = inc(u,t); p[j + h / 2] = inc(u,MOD - t); w = mul(w,wn); } } }
一開始的二進制翻轉要設置成\(i < L - 1\)
而後\(h\)是步長,最底層是\(2\)
\(k\)是每一塊的起點
\(j\)遍歷這一塊的前一半,和後一半的依次進行蝴蝶操做
若是是逆DFT,那麼要除上模長
單位復根的本質是把一個單位圓\(2^{k}\)等分,而複數相乘的結果是模長相乘,幅角相加
換成原根就行了,快樂
MTT不會,再見
tf表示正變換,utf是逆變換
\(tf(A) = (A_{0} + A_{1},A_{0} - A_{1})\)
\(utf(A) = (\frac{A_{0} + A_{1}}{2},\frac{A_{0} - A{1}}{2})\)
\(tf(A) = (A_{0},A_{0} + A_{1})\)
\(uft(A) = (A_{0},A_{1} - A_{0})\)
注意對於或卷積一般有一類題須要在每一次卷積用$2^{n} $的複雜度還原出\(2^{n} - 1\)的值(就一個位置)
方法就是有奇數個0加上這個位置的值,偶數個0減去這個位置的值
\(tf(A) = (A_{0} + A_{1},A_{1})\)
\(utf(A) = (A_{0} - A_{1},A_{1})\)
來一個FWT的板子(異或)
void FWT(int *a) { for(int i = 1 ; i < (1 << N) ; i <<= 1) { for(int j = 0 ; j < (1 << N) ; j += (i << 1)) { for(int k = 0 ; k < i ; ++k) { int t0 = a[j + k],t1 = a[j + k + i]; a[j + k] = inc(t0,t1); a[j + k + i] = inc(t0,MOD - t1); } } } } void IFWT(int *a) { for(int i = 1 ; i < (1 << N) ; i <<= 1) { for(int j = 0 ; j < (1 << N) ; j += (i << 1)) { for(int k = 0 ; k < i ; ++k) { int t0 = a[j + k],t1 = a[j + k + i]; a[j + k] = mul(inc(t0,t1),Inv2); a[j + k + i] = mul(inc(t0,MOD - t1),Inv2); } } } }
來自VFK的論文。。
本質是或卷積,然鵝。。。代碼短啊!!
本質上是求\(f[S] = \sum_{T \in S} g[T]\)
用一個dp實現,咱們按位考慮,從最低位開始數i - 1位已經考慮完了,我把第\(i\)位與它不一樣加進來
逆變換改爲減掉就行了
void FMT(T *a,T ty) { for(int i = 1 ; i < L ; i <<= 1) { for(int j = 0 ; j < L ; ++j) { if(j & i) { a[j] = a[j] + ty * a[j ^ i]; } } } }
而後是集合冪級數,我第一次作到這題仍是WC2018(然鵝不會就是了
咱們要求的是這個東西
\(h[S] = \sum_{T \in S}g(T)f(S \oplus T)\)
我會子集枚舉!!!
可是咱們要會一個\(n^{2}2^{n}\)的算法才能夠得到滿分
設一個多項式\(g(S)x^{|S|}\),最後答案就是\(h(S)x^{|S|}\)
具體是設一個二維的數組,\(g[i][S]\),而後進行\(FMT\),點值相乘的時候\(n^2\)枚舉\(i,j\)用\(g(S)f(S)x^{i}x^{j}\)更新\(h(S)x^{i + j}\)最後再每一層都捲回去就行了
衆所周知sjq是個肥宅的女孩子
因此她補兩天的感受很累,打算寫一些邊角餘料的知識點糊弄過去
和cdq分治很像?但不是一個東西啦
Solve(int l,int r,int ql,int qr)
表示我二分的區間是\(l,r\),而詢問的區間是\(ql,qr\)
複雜度?固然是\(q \log V\)的,\(V\)是值域,由於每一個詢問往下走都走了\(\log V\)層
(我應該放到圖論那裏的)
建樹點的個數應該是2倍的詢問點(上界)
建樹方法是按dfn排序後,維護右鏈,求插入點和棧頂點的lca,若是棧頂深度大於插入點則不斷彈出,在最後一個深度大於等於插入點的地方可能會被修改lca
以後若是lca不存在則插入lca
注意若是不須要樹而須要虛樹的邊長和,直接把虛樹按照dfn排序後,相鄰兩個點距離相加就是二倍的虛樹邊長和
void build_auxtree(int aN) { num=aN; sort(aux+1,aux+num+1,cmp); stk[top=0]=0; siji(i,1,aN) { int u=aux[i]; if(!top) { stk[++top]=u; faAux[u]=0; } else { int Lca=lca(stk[top],u); while(dep[stk[top]]>dep[Lca]) { if(dep[stk[top-1]]<=dep[Lca]) { faAux[stk[top]]=Lca; } --top; } if(Lca!=stk[top]) { faAux[Lca]=stk[top]; aux[++num]=Lca; stk[++top]=Lca; } stk[++top]=u; faAux[u]=Lca; } } sort(aux+1,aux+num+1,cmp); }
\(fa[i][j]\)表示第\(i\)個點往上走\(2^{j}\)步是哪一個點,若不存在則爲0
把兩個點調整到同一深度,而後同時往上跳
(能夠同時維護鏈上最小值,很好用)
維護一個序列,求dfn序的同時在遍歷完每一個兒子以後把父親加進去,兩點之間的lca就是兩點之間的最小深度的點,能夠作到\(O(1)\)查詢
今天開始數據結構吧
第一天就瞎寫一些簡單的
按照這個進度我以爲我要複習不完了(由於頹)
這個真的是數據結構麼。。。
單調隊列能夠實現一個區間內的最大值從遠到近排序(右端點遞增,左端點遞增)
而單調棧實現的差很少
單調隊列像一個開口的單調棧
int getfa(int u) {return fa[u] == u ? u : fa[u] = getfa(fa[u]);}
能夠帶權維護不少東西,例如食物鏈那題
priority_queue默認返回最大值
手寫堆的方法是把新加入的數放在最後一個,而後若是根小於它,則交換它和根
struct BIT { int tr[MAXN],s; int lowbit(int x) {return x & (-x);} void insert(int x,int v) { while(x <= s) { tr[x] += v; x += lowbit(x); } } int query(int x) { int res = 0; while(x > 0) { res += tr[x]; x -= lowbit(x); } return res; } };
能夠維護一個前綴和,有了前綴和的同時能夠查詢區間和
減掉原來的,直接插入
給一段區間\([l,r]\)加\(d\),至關於在\(l\)處加上\(d\),在\(r + 1\)處減去\(d\)
jiukeyile而後查詢一段前綴和便可得到單點的值
咱們仍是考慮區間加以後如何獲得前綴和,前綴和相減就是區間和
仍是把加改爲差分,一個\(p\)加上\(d\)的形式,給前\(r\)個數帶來的貢獻是
\((r - p + 1) * d\)
咱們能夠用兩個樹狀數組,一個維護一個前綴里加上過的差分的和,一個維護\((p - 1) * d\)的和,就能夠了
while寫兩層便可實現,可得到一個\([1,x]\)和\([1,y]\)的矩形內的值的前綴和
更新log個位置的最大值便可,用它只是由於太好寫了,寫個線段樹不愉快
就是相似邊表同樣,算完hash以後再給這個值取模一個較小的數扔進邊表裏,扔的是這個數的取模前的值
這個太廣泛了,並且有不少變種,有你從未體驗過的全新玩法
一般能夠優化一類dp,例如把一段數分紅兩個集合\(dp[i][j]\)表示第一個集合的最後一個位置,和第二個集合的最後一個位置
不說了,這個會寫就很簡單,不會寫的題死也想不到這麼維護的
平面上有不少條直線,而後詢問一個位置的最小值
咱們每一個區間維護一個優點線段,就是這個區間內暴露最多的線段
若是新加入的線段兩端都大於優點線段,就不要
不然會有一個交點,咱們取較長的那個做爲優點線段,而後另外一個額外處理
這樣一次是\(O(\log n)\)的
能夠維護一個序列,而且能夠取出一段序列,實現區間翻轉移動之類的操做
我通常寫無旋Treap
每次往深度大的鏈頂跳
選擇深度大的一個兒子進行剖分
能夠在有關深度的複雜度作到線性
今天打包字符串類數據結構(和一些算法)
求一個\(nxt\)數組,\(nxt[i]\)表示\([1,nxt[i]]\)的字符串和\([i - nxt[i] + 1,i]\)的字符串相等
求法是找到從\(nxt[i - 1]\)開始跳\(nxt\)鏈,若是鏈上某一個位置\(p\)使得\(s[p + 1] = s[i]\)則\(nxt[i] = p + 1\),不然\(nxt[i]\)就是0
這個用來求最長迴文子串
複雜度$ O(n)$
咱們爲了方便,能夠給每一個字符中間插入一個特殊字符,來同時考慮奇數迴文串,和偶數迴文串
設\(r[i]\)爲\(i\)向兩邊擴展的最大長度使得\([i - r[i] + 1,i + r[i] - 1]\)是一個迴文串
咱們記錄一個擴展到最遠的位置\(mx\),和這個位置的中心\(p\)
當咱們遇到下一個位置\(i\),能夠用\(min(mx - i + 1,r[2 * p - i])\)來做爲初始的\(r[i]\)更新
這樣每次\(mx\)不降,是\(O(n)\)的
這個用來求每一個位置和1的最長公共前綴
至關於砍了一半的manacher,咱們也記錄擴展到最遠的位置\(mx\)和一個開頭\(p\)
新的位置\(i\)用\(min(mx - i + 1,r[i - p])\)做爲擴展的位置
求循環串的最小表示法
用兩個指針\(i,j\)和這兩個開頭能匹配的長度\(len\)
若\(i\)失配了,則\([i,i + len]\)都是不合法的位置
\(j\)失配同理
若是\(i,j\)相等則把其中一個+1
若是有一個大於字符串長度則退出
一個字符串是Lyndon word當它是本身全部後綴中的最小值
若是字符串\(s\)和字符\(c\)組成\(sc\)是一個Lyndon Word的前綴,那麼\(d > c\),則\(sd\)是個Lyndon Word
維護上一個未分解的位置是\(last\),看last開頭的下一個Lyndon 串是否被循環構造
int s = 1,t = 2,last = 1; while(last <= LEN) { s = last;t = s + 1; while(1) { if(str[s] == str[t]) ++s,++t; else if(str[s] < str[t]) s = last,++t; else { do { last += t - s; out(last - 1);putchar(' '); }while(last <= s); break; } } }
7.9 upd
如何快速求出每一個後綴的Lyndon分解
首先須要把後綴排序(固然更方便的是直接二分哈希求lcp,我就是這麼寫的,會多一個log,冬令營的課件上彷佛有\(O(n)\)作法,不太懂)
咱們用一個棧,求出後綴\([i + 1,N]\)的lyndon分解後,咱們新加一個字符\(s[i]\),若是這個串比前一個lyndon串小,就把這個串和後一個串合併起來
由於若\(u,v\)都是lyndon串,\(u < v\),則\(uv\)也是lyndon串,由於v嚴格小於本身全部後綴,\(u < v\),u也會小於新加進來的全部後綴
7.9 updend
每一個點連出的邊兩兩不一樣,邊權是字符
爲每一個trie樹上的節點找一條前綴節點表示若在此處失配能同時匹配的最大的深度到哪,顯然這個節點是惟一的
新建一個0號點往根連字符集的邊
這個節點就是父親節點的前綴節點的該邊,若不存在則繼續跳前綴節點,相似kmp
或者一開始就補齊全部邊
AC自動機的每一個節點也能夠惟一的表示多模式串匹配中的狀態
每一個節點維護
last表示當前最後一個節點
每次新加一個節點,則在last鏈中沒有該字符的節點上連一條邊
若last遍歷到空,則當前節點的par是根
若沒有,則看當前指針p該字符的出邊指向節點q是不是len[q] = len[p] + 1
不然複製一個q,長度設置爲len[p + 1],cnt設乘0,其他不變,q與當前節點的par都設置成複製的節點
把last設置爲當前節點
反串的後綴自動機的par樹等於正串的後綴樹
7.12 upd
建上兩個根,一個表示偶數點回文串的根,一個表示奇數點回文串的根,偶數點回文串的根的父親節點是奇數點回文串的根
而後咱們初始在偶數點回文串的根,若是失配則不斷跳父親
若是存在一個迴文串,即當前節點維護的迴文串長度爲len,當新加一個節點後,存在\(s[i - len - 1] == s[i]\),那麼就能夠從當前節點延伸出去一條值爲\(s[i]\)的邊
那麼如何更新父親節點
一樣的相似AC自動機,父親節點的後綴節點的該邊,咱們也不斷的跳父親鏈直到找到一個使得又一個\(s[i - len - 1] == s[i]\)的地方,若是父親是奇數根則默認這個點的父親是偶數根
能夠在前面插入,也能夠在後面插入,是相似的,具體能夠參考
而回文樹的fail樹,從底到根表示以這個位置結尾的迴文串各是什麼
板子:APIO2014迴文串
CF上有一個技巧
感受這個技巧就是應用了以一個位置i爲結尾的迴文串,構成的迴文串長度造成了\(\log n\)個等差數列
而後一個等差數列,若首項爲\(a\),公差是\(d\),則能夠轉移的位置是\(i - a - d\),\(i - a - 2d\),\(i - a - 3d\)...這一連串的位置,然而咱們能夠從\(i - d\)的位置維護一個\(series-ans\),這個位置的\(i - a - d\)就是\(i\)的\(i - a - 2d\)
關於爲何不是\(i - a\)?由於不斷向上找最後找到的必定是偶數根或者奇數根,沒有長度,對統計沒有意義,因此最後全部位置仍是會被考慮到
7.12 upd end
我jio得要複習不完了(還有十天……我數論還沒開)
一個是新樹的根,一個是舊樹的根,把新樹的根分配一個節點,而後複製的和舊樹如出一轍,再進行修改
將修改遞歸到左兒子或右兒子繼續操做
這是單點修改
對於主席樹的區間修改來講,要用樹狀數組套主席樹,每次修改log個樹根,查詢的時候也是
Spilt的時候每次新建一個節點,Merge的時候也是
炸內存愉快
每次也是新建一個節點,把以前節點的信息都複製過來
可並堆,具備堆的性質(根的權值大於兩個兒子)
每一個節點額外維護一個\(dis\)表示到最遠的左兒子的距離
每次優先和右兒子合併
若是右兒子的dis大於左兒子的dis就交換
維護一個平面上的點集
每次兩維(或更多維)交替着來,每次按照須要劃分的那一維排序,而後中位數的點做爲這個節點維護的點,以後分到兩邊處理
能夠維護不少東西,一般是維護這個區間點集橫座標和縱座標的範圍,便於剪枝
正交範圍複雜度是\(O(n^{\frac{k - 1}{k}})\),一般\(k = 2\),複雜度$O(\sqrt{n}) $
LCT裏分實邊和虛邊,每一個節點往下只連一條實邊,其他都是虛邊
實邊把樹分紅了好幾條鏈,咱們把這些鏈當作一個平衡樹維護,而這個平衡樹的頂的父親就是虛邊鏈接的父親(實際上,在樹中這個父親是這個平衡樹最左節點的父親,而非根的父親)
用Splay維護每條樹鏈,用Splay實現一個把每一個點轉到樹根的操做
實現的功能是構造一條x到根的路徑
1.若是x有實邊,斷掉,方法是把x轉到根,而後斷掉右兒子
2.找到路徑的父親(其實是Splay中最左節點的父親),把父親轉到根,斷掉右兒子,換成x所在splay的根(也就是切換偏心邊)
3.平衡樹的根不是空節點,說明沒有連到根,繼續
找到x所在樹的根
先Access(x),而後找到最左節點
先Access(x),而後該平衡樹翻轉
把x變成根,而後加一條虛父親到y
把x變成根,而後Access(y),把y旋到根,此時x是y的左兒子,斷掉便可(同時修改y的左兒子和x的父親
把x變成根以後Aceess(y)便可獲得一棵平衡樹
通常有些題不是特別須要MakeRoot,能夠簡化一下代碼
若是須要選兩個點之間的鏈就拆成兩段作就行了
從上到下每一行長度遞減,若是是遞增的樣表,則每一個數要大於它上面的值和左邊的值
維護方法比較暴力,就是每一行二分一個插入位置,若是是空的就插入,若是有值,先插入,再把這個值扔到下一行去繼續插入
有個結論是把排序方法反過來能夠獲得樣表的轉置
還有一個公式是鉤長定理
有n個數的楊氏矩陣的個數爲(固定了形狀)
設每一個格子鉤子長度爲\(h(x,y)\),鉤子長度是每一個點右邊的格子數+下邊個格子數+1
答案是\(\frac{n!}{\prod h(x,y)}\)
還有半標準楊表(行單調不增,列單調減)
\(\prod_{h(i,j)} \frac{r + j - i}{h(i,j)}\)
其中\(r\)是值域的大小
複雜度\(n \log\log n\)
每遇到一個質數,就用這個質數的倍數去更新區間裏全部的數
對於須要篩區間裏的質數且區間長度較小而左右端點較大時就只能用埃氏篩而不是歐拉篩
例如
\(10^9 \leq l \leq r,r - l \leq 10^{7}\)
對於每一個數\(i\),枚舉質數\(p\),把\(ip\)標記爲合數,若是\(p | i\)則退出
這樣每一個合數只在最小的質數那裏被篩了一次,是\(O(n)\)的
能夠用來預處理積性函數,互質的狀況顯然乘起來就好,不互質考慮這個質數帶來的貢獻便可
若\(a,p\)互質,且\(p\)是質數能夠獲得\(a^{p - 1} \equiv 1 \pmod p\)
若\(a,m\)互質,\(m\)不必定是質數,能夠獲得\(a^{\varphi(m)} \equiv 1 \pmod m\)
若\(a,m\)不互質,若\(c > \varphi(m)\),能夠獲得\(a^{c} = a^{c \% \varphi(m) + \varphi(m)} \pmod m\)
求\(ax +by = g\)的一組解
首先咱們能夠轉化成求\(\frac{a}{g}x + \frac{b}{g}y = g\)因而咱們只剩下\(ax +by = 1\)的方程要解了
考慮gcd的求法
若存在一組\(ax + by = 1\)
上一次遞歸中求出了\(bx' + a \% by' = 1\)
能夠獲得
\[ bx' + ay' - b\lfloor \frac{a}{b}\rfloor y' = 1 \\ ay' + b(x' - \lfloor \frac{a}{b} \rfloor y') = 1 \]
因而\(x = y'\),\(y = x' - \lfloor \frac{a}{b} \rfloor y'\)
能夠用來求逆元,求線性同餘方程
若是有一組方程
\(x \equiv a_{1} \pmod {m_{1}}\)
\(x \equiv a_{2} \pmod{m_{2}}\)
\(\cdots\)
\(x \equiv a_{n}\pmod {m_{3}}\)
其中\(m_{1}m_{2}...m_{n}\)兩兩互質
咱們設\(M = m_1m_{2}\cdots m_{n}\)
設\(M_{i} = \frac{M}{m_{i}}\)
求出\(M_{i}t_{i} \equiv 1 \pmod {m_{i}}\)
\(x = a_{1}t_{1}M_{1} + a_{2}t_{2}M_{2} + \cdots + a_{n}t_{n}M_{n}\)
在\([1,M - 1]\)內有且只有一個解,剩下的每一個解都要加上M
\(ax \equiv b \pmod m\)
能夠這麼認爲
\(ax = b + mk\),k是任意整數
這個方程有解的條件是\(gcd(a,m) | b\)
因而能夠把兩邊同時除以\(gcd(a,m)\)是等價的
\(\frac{a}{g}x = \frac{b}{g} + \frac{m}{g}k\)
而後把這個當成新的\(a,b,m\),這個時候認爲\(a,m\)互質,求出\(a\)在\(m\)意義下的逆元,
因而\(x \equiv \frac{b}{a} \pmod m\)
因而咱們能夠認爲全部的形式都是
\(x \equiv a \pmod {m}\)
而後怎麼求這個呢
假如
\(x \equiv a_{1} \pmod {m_{1} }\)
\(x \equiv a_{2} \pmod{m_{2} }\)
\(x = a_{1} + km_{1}\)
\(x = a_{2} - hm_{2}\)
\(a_{1} + km_{1} = a_{2} - hm_{2}\)
\(km_{1} + hm_{2} = a_{2} - a_{1}\)
爲了解這個方程方便,咱們仍是能夠兩邊都除上\(gcd(m_{1},m_{2})\)
而後咱們解得了一個\(k\),因而新的\(x \equiv a_{1} + km_{1} \pmod {lcm(m_{1},m_{2})}\)
因而這麼兩兩合併下去便可
因爲sjq過於頹,她把該一天寫完的分紅兩天寫完,而且理所固然的認爲複習不完就複習不完,國賽打鐵就打鐵吧
\(A^{x} \equiv B \pmod C\)
基礎版\(A,C\)互質
咱們把\(A^{0}\)到\(A^{\varphi(C) - 1}\)分紅\(m = \sqrt{C}\)個一組
對於第一組,暴力處理出組內\(A^{y}B\)的值,存在一個哈希表裏
剩下組中的值至關於\(A^{im - y} \equiv B \pmod C\)
咱們把\(A^y\)移過去,就是\(A^{im} \equiv BA^{y} \pmod C\),因而每組能夠只詢問一個\(A^{im}\)看是否存在
非基礎版,\(A,C\)不互質
\(A^{x} \equiv B\pmod C\)
\(A^{x} + Ck = B\)
咱們每次除掉一個gcd(A,C),若\(B\)不能整除這個gcd,則無解
\(\frac{A}{d_{1}} A^{x - 1} + \frac{C}{d_{1}} k = \frac{B}{d_{1}}\)
這個時候\(\frac{C}{d_{1}}\)可能還和\(A\)不互質,咱們就一直除下去
直到互質爲止
設\(C_{n} = \frac{C}{d_{1}d_{2}\cdots d_{n}}\)
\(B_{n} = \frac{C}{d_{1}d_{2}\cdots d_{n}}\)
\(D = \frac{A}{d_{1}d_{2}\cdots d_{n}}\)
獲得了
\(A^{x - n} \equiv \frac{B}{D} \pmod C\)
因而咱們又回到了剛剛那個問題
每一個質數內能夠找到一個數\(g\)
使得\(g^{1}\)到\(g^{p - 1}\)構成了\([1,P - 1]\)裏的每一個數
這個原根一般很小,能夠暴力求,求得方法就是判每一個\(a|P - 1\),a不爲1
\(g^{\frac{P - 1}{a}}\)是否等於1,若等於1則g不是原根
\(x^{K} \equiv a\pmod P\)
爲了簡單一些……只討論質數……非質數的實在過於難寫
能夠參考這裏
找到\(g^{t} = a\),這個用BSGS解
設\(x = g^{i}\)
求一個指標能夠獲得
\(g^{iK} \equiv g^{t} \pmod P\)
\(iK \equiv t \pmod {P - 1}\)
這個只須要解一個同餘方程就行了
多是一些線代相關?(得了吧你會線代嗎)
矩陣乘法以前好像說了……
有一組方程有\(n\)個變量,和\(n\)個方程
咱們在第\(i\)次循環中,排名在\(i\)之後且\(x_{i}\)係數最大的方程,使其變成第\(i\)個方程
而後用這個方程消掉排名在\(i + 1\)及之後的方程第\(i\)項的係數
若是某一次發現\(x_{i}\)係數最大就是0,那麼這個位置能夠任意取值,題目裏可能會有一些無解之類的多是這種狀況
行列式是一個排列\(p_{1},p_{2}...p_{n}\),求逆序對數爲\(r(P)\)
求\(\sum (-1)^{r(p_{1},p_{2},p_{3}...p_{n})}a_{1,p_{1}}a_{2,p_{2}}...a_{n,p_n}\)
求行列式的通常方法是把矩陣經過基礎行變換或者列變換把矩陣消成一個上三角矩陣,而後對角線上的值相乘便可
具體的變換是
1.行列交換,行列式不變 就是\(a_{i,j}\)變成\(a_{j,i}\)(可是通常用不上這個)
2.行列式一行的因子能夠提出 就是一行都除\(k\),求完這個行列式後再乘上\(k\)
3.兩行互換,行列式反號
4.將一行的倍數加到另外一行上,行列式不變
好像寫的話只須要34就夠了
入度矩陣對應的外向樹,出度矩陣對應着內向樹(都是指向父親的邊的事是出度或者入度)無根樹就是兩條有向邊都加上
有向樹必須刪掉根所在的那一行和一列,無根樹能夠任意
而後對於這\(n - 1\)階的矩陣求一個行列式就好了,也叫主子式
建單位矩陣,和要求逆的矩陣同時進行求行列式用到的變換
注意要麼只換兩行要麼只換兩列,不能都換(不過通常你都是在換行……不會換列……)
目標是把要求逆的矩陣消成單位矩陣,此時的單位矩陣就是逆矩陣
就是每加入一個數,從最高位到最低位遍歷,若是有這一位就和這個數異或一下消掉
一個\(k\)個數組成的線性基能夠構成\(2^{k}\)個不一樣的數\([0,2^{k} - 1]\)
帶修改的線性基能夠經過額外維護一個二進制數表示這個數是由哪些數異或而成的
若是要修改第\(k\)個,且有包含第\(k\)個的數值爲0,則能夠用這個0和全部包含第k個數的值異或一下,再將修改後的值嘗試插入線性基
若包含第k個的數值爲線性基中的數,則選擇最小的那個數,和前面的更新,把這個數刪除,而後嘗試插入線性基
天哪竟然只剩7天了,真的複習不完了
今天是數論函數變換,因爲我很喜歡這個東西,因而我決定去51nod刷點數論函數題再回來寫(然鵝窩根本作不出來那些題= =
\(g(n) = \sum_{d|n}f(d)\)
\(f(n) = \sum_{d | n}\mu(\frac{n}{d})g(d)\)
\(\mu\)函數你們很熟悉再也不贅述
這個雖然能夠暴力推式子證實,可是有比較好的思路就是容斥
\(g\)是什麼,\(g\)是在質因數分解的意義下的一個高維前綴和
那麼,咱們把這個高維前綴和嘗試推掉其中的幾維,也就是這一維下標-1,若是推掉了奇數維就是+1,偶數維就是-1
這也就是\(\mu(d)\)的意義了,\(d\)是必定是若干個質數相乘
還有另外一個形式!
\(g(n) = \sum_{n | d} f(d)\)
\(f(n) = \sum_{n | d} \mu(\frac{d}{n})g(d)\)
就是後綴和和前綴和的區別了,差很少的。。。
對於\(g(n) = \sum_{d | n}f(d)\)寫過一個很蠢的\(O(n \log \log n)\)求法,實際上很簡單。。可是裝模做樣的寫了一堆
積性函數均有\(f(1) = 1\)
能夠經過討論質數的指數冪應該的函數值從而獲得整個函數值
\(h(n) = \sum_{d | n}f(\frac{n}{d}) g(d)\)
則\(h = f * g\)
有交換律,結合律,分配律,還有單位1
還有\(f,g\)若是都是積性函數,則卷積後的\(n\)也是矩形函數,這個比較常見……
\(\varepsilon(u) = [u == 1]\)就是單位1
然而數論題呢~其實沒怎麼用到莫比烏斯反演,主要仍是……用到了一些經常使用的卷積,固然若是你細心的話能夠發現這些卷積能夠經過莫比烏斯反演推導而來,然而這裏直接寫了
\(d(n)=\sum_{d|n}1\)約數個數和
\(\sigma(n) = \sum_{d|n} d\)也就是\(d * 1\)
\(n = \sum_{d|n} \varphi(d)\) 這個的意義是\(n/d\)乘上和\(d\)互質的數,這樣就計算了和每一個數和\(n\)gcd爲\(n / d\)的方案數
這個時候反演一下能夠獲得
\(\varphi(n) = \sum_{d | n}\frac{n}{d}\mu(d)\)
\(\varepsilon(n)= \sum_{d|n} \mu(d)\)這是最經常使用的一個!由於它能夠把一個判別式轉化成代數式!很神奇!
感受技巧挺多的(然而我作題少QAQ)
\(i\)之內和\(i\)互質的數的的和是\(\frac{i \times \varphi(i)}{2}\),1除外,1的話就是1
n之內無平方因子數能夠經過\(\sum_{i = 1}^{\sqrt{N}} \mu(i) \lfloor \frac{N}{i^{2}}\rfloor\)
假如咱們有一個積性函數要求和
不會
假如咱們有個積性函數,在和一個已知函數卷積的時候,卷出來的函數能夠\(O(1)\)求和
嗯??????感受事情變奇妙了
那麼咱們以最普通可愛的\(\mu\)來舉例吧
\(\varepsilon(n) = \sum_{d | n} \mu(d)\)
那麼咱們嘗試列一個式子
\[ \sum_{i = 1}^{n} [i == 1] = \sum_{i = 1}^{n} \sum_{d | i} \mu(d) \]
而後把這個式子改成枚舉一個\(t\),再枚舉\(i\),求的是\(it\)這個倍數在\(n\)之內的這樣的\(\mu(i)\)
而後就變成了
\[ \sum_{i = 1}^{n} [i == 1] = \sum_{t = 1}^{n} \sum_{i = 1}^{\lfloor \frac{n}{t} \rfloor} \mu(i) \]
咦……若是設\(M(n) = \sum_{i = 1}^{n} \mu(i)\)
後面的就是
\[ \sum_{i = 1}^{n} [i == 1] = \sum_{t = 1}^{n} M(\lfloor \frac{n}{t} \rfloor) \]
那麼,只有\(t = 1\)的時候,纔是咱們要求\(M(n)\)
這樣的話,咱們再轉換成
\[ M(n) = 1 - \sum_{t = 2}^{n} M(\lfloor \frac{n}{t} \rfloor) \]
這樣的話,咱們只要處理對後面的部分遞歸下去就行了,一般爲了快一點咱們會使用哈希,而且預處理出1e7之內的前綴和
好像還有高階小量啥的,不太懂,反正複雜度是\(O(n^{\frac{2}{3}})\)的
一般還能夠用到的卷積有
\(n = \sum_{d | n}\varphi(d)\)能夠用來求\(\varphi(n)\)函數的前綴和
還有……
\(n^{2} = \sum_{d|n}d\varphi(d) \frac{n}{d}\)
能夠用來求\(d\varphi(d)\)的前綴和……
可是這個限制很大,只有有一個好求的卷積後的函數才能夠快速出解……
留個坑!必定補!我去翻zsy博客了!qwq
天哪我竟然立刻要去國賽了還要學新知識點,感受要廢
精妙無比可是根本用不上的原式
\[ f(n) = \sum_{i = 0}^{n} (-1)^{i}\binom{n}{i}g(i) \\ g(n) = \sum_{i = 0}^{n} (-1)^{i}\binom{n}{i}f(i) \]
不精妙可是很是實用的另外一種式子
\[ f(n) = \sum_{i = 0}^{n}\binom{n}{i} g(i) \\ g(n) = \sum_{i = 0}^{n}(-1)^{n - i}\binom{n}{i} f(i) \]
不精妙可是很是實用的另外一種式子2
\[ f(k) = \sum_{i = k}^{\infty} \binom{i}{k}g(i) \\ g(k) = \sum_{i = k}^{\infty} (-1)^{i - k}\binom{i}{k} f(i) \]
這兩種式子分別表明什麼呢
第一種是至多和剛好的轉化
\[ f(n) = \sum_{i = 0}^{n}\binom{n}{i} g(i) \\ g(n) = \sum_{i = 0}^{n}(-1)^{n - i}\binom{n}{i} f(i) \]
設\(g(n)\)表示剛好有\(n\)個元素合法,\(f(n)\)表示至多有\(n\)種元素合法,則至多的每一種方案是從剛好\(i\)箇中轉移過來的
舉個栗子
有k個方格,染上剛好n種顏色,每種顏色必須出現
這個時候,至多有\(a\)種顏色很好算,就是\(f(a) = a^{k}\)
這樣直接套進這個式子就能夠算出來剛好了!
爲了方便書寫,我把它叫至多,事實上你能夠認爲它叫「欽定」,或者「硬點」
由於真正的「至多」,就是\(f(n) - f(n - 1)\),這裏顯然不是這樣
什麼?爲何不是這樣
例如「欽定」填3種顏色,和「欽定」填2種顏色,填3個格子各有什麼區別
第一種是
1 1 1 & 1 1 2 & 1 2 1 & 1 2 2
2 1 1 & 2 1 2 & 2 2 1 & 2 2 2
1 1 3 & 1 2 3 & 2 1 3 & 2 2 3
1 3 1 & 1 3 2 & 2 3 1 & 2 3 2
3 1 1 & 3 1 2 & 3 2 1 & 3 2 2
3 3 1 & 3 3 2
3 1 3 & 3 2 3
1 3 3 & 2 3 3
3 3 3
第二種是
1 1 1 & 1 1 2 & 1 2 1 & 1 2 2
2 1 1 & 2 1 2 & 2 2 1 & 2 2 2
顯然,三種顏色填三個格子方案數是\(3! = 6\)
然而\(27 - 8 \times \binom{3}{2} = 3\)
少到哪裏了?
就少在,3個格子只出現了一種數,被這兩種狀況減了兩遍
第二種是至少和剛好的轉化
\[ f(k) = \sum_{i = k}^{\infty} \binom{i}{k}g(i) \\ g(k) = \sum_{i = k}^{\infty} (-1)^{i - k}\binom{i}{k} f(i) \]
你確定會熟悉(至少0個 - 至少1個 + 至少2個....)的公式,請帶入\(k = 0\),你就會明白,它沒有組合數是由於\(\binom{i}{0} = 1\),因而,你們在作至少\(k\)個\(k\)不爲0的時候,記得追根溯源,把沒法省略的組合數補上
設\(g(n)\)是剛好\(n\)個的方案數,\(f(n)\)是至少\(n\)個的方案數
在這裏順便介紹一種常見的容斥,含有上界的計數,即對於\(n\)個數,只能選\([0,a]\)之間,上界給定是\(S\),求方案數
方法就是枚舉至少有幾個數不合法,而後剩下的數隨便分配
固然,這裏也不要當成真正的「至少」,你也能夠叫「欽定」,或者硬點
第一類斯特林數的組合意義是把\(n\)個元素放在\(m\)個環裏
遞推方法是
\[ \begin{bmatrix}n\\ m\end{bmatrix} = \begin{bmatrix} n - 1 \\ m - 1\end{bmatrix} + (n - 1)\begin{bmatrix} n - 1 \\ m \end{bmatrix} \]
組合意義就是,要麼這個數新建一個環,要麼插在任意一個數的前面
一點小性質
\[ n! = \sum_{i = 0}^{n} \begin{bmatrix} n \\ i \end{bmatrix} \]
由於斯特林數本質是環排列,能夠和置換對應
(翻了翻yyb的博客抄來了一點別的……事實上第一類我跟本不熟……)
\[ x^{\underline{n}} = \sum_{i = 0}^{n} \begin{bmatrix}n\\ i\end{bmatrix}(-1)^{n -i}x^{i} \]
其中\(x^{\underline{j}}\)認爲是\(\frac{x!}{(x - j)!}\),不過咱們要從\(x\)減下去那麼乘,有些時候沒有逆元
證實(也是抄的)
利用數學概括法\(n = 0\)時
\[ 1 = \begin{bmatrix}0 \\0 \end{bmatrix}(-1)^{0}x^{0} \]
而後
\[ \begin{align*} x^{\underline{n + 1}} &= (x - n)x^{\underline{n}}\\ &= (x - n) \sum_{i = 0}^{n}\begin{bmatrix}n \\ i\end{bmatrix}(-1)^{n - i}x^{i}\\ &= \sum_{i = 1}^{n + 1}\begin{bmatrix} n \\i - 1\end{bmatrix}(-1)^{n - i - 1}x^{i} - n\sum_{i = 1}^{n + 1}\begin{bmatrix}n \\ i\end{bmatrix}(-1)^{n - i}x^{i} \\ &= \sum_{i = 1}^{n + 1}\begin{bmatrix} n \\i - 1\end{bmatrix}(-1)^{n - i + 1}x^{i} + n\sum_{i = 1}^{n + 1}\begin{bmatrix}n \\ i\end{bmatrix}(-1)^{n - i + 1}x^{i} \\ &= \sum_{i = 1}^{n + 1}(\begin{bmatrix}n \\ i - 1 \end{bmatrix} + n\begin{bmatrix} n \\ i \end{bmatrix})(-1)^{n + 1 - i}x^{i} \\ &= \sum_{i = 1}^{n + 1}\begin{bmatrix}n + 1 \\ i \end{bmatrix}(-1)^{n + 1 - i}x^{i} \end{align*} \]
還有一個式子
\[ x^{\bar{n}} = \sum_{i = 0}^{n}\begin{bmatrix}n \\ i \end{bmatrix}x^{i} \]
能夠相似的證實
\[ \sum_{i = 0}^{n} \begin{bmatrix}n \\ i\end{bmatrix}x^{i} = \prod_{i = 0}^{n - 1}(x + i) \]
從遞推式考慮,要麼是\(m - 1\)變成\(m\),會有一個\(x\),要麼是從\(n - 1\) 變成\(n\)會乘上一個\(n - 1\),從第一行往下推便可獲得這個式子
因而咱們就能夠分治FFT求第一類斯特林數了!
(抄來的一點倍增方法)
\(F_{n}(x) = \prod_{i = 0}^{n - 1}(x + i)\),有\(F_{2n}(x) = F_{n}(x)F_{n}(x + n)\)
考慮用\(F_{n}(x)\)去求\(F_{n}(x + n)\)
\[ \begin{align*} F_{n}(x + n) &= \sum_{i = 0}^{n}a_{i}(x + n)^{i} \\ &= \sum_{i = 0}^{n}a_{i}\sum_{j = 0}^{i}\binom{i}{j}n^{i - j}x^{j} \\ &= \sum_{i = 0}^{n}x^{i} \sum_{j = i}^{n}\binom{j}{i}n^{j - i}a_{j} \end{align*} \]
第二類斯特林數的組合意義是把\(n\)個不一樣的數放到\(m\)個相同的盒子裏,且每一個盒子必須有數
\[ \begin{Bmatrix}n\\ m\end{Bmatrix} = \begin{Bmatrix}n - 1\\ m - 1 \end{Bmatrix} + m\begin{Bmatrix}n - 1\\ m \end{Bmatrix} \]
第二類斯特林數能夠轉化成乘方
\[ \begin{Bmatrix}n\\ m\end{Bmatrix} = \frac{1}{m!}\sum_{i = 0}^{m} (-1)^{m - i}\binom{m}{i} i^{n} \]
表示選了至多\(i\)個盒子放東西
這樣的話咱們反演一下能夠獲得
\[ \begin{Bmatrix}n\\ m\end{Bmatrix}m! = \sum_{i = 0}^{m} (-1)^{m - i}\binom{m}{i} i^{n} \\ m^{n} = \sum_{i = 0}^{m}\binom{m}{i}\begin{Bmatrix}n \\i \end{Bmatrix}i! \]
第一個式子也是FFT預處理第二類斯特林數的方法
因爲斯特林數在\(n < m\)的時候答案爲0,因此能夠第二個式子的上界也能夠是n,在指數遠小於底數的時候做用很大
天然數冪和也能夠用有關第二類斯特林數的一個公式
\[ \begin{align*} S(n) &= \sum_{i = 1}^{n}i^{k} \\ &= \sum_{i = 1}^{m}\sum_{j = 0}^{i} \begin{Bmatrix}k \\ j\end{Bmatrix} j! \binom{i}{j} \\ &= \sum_{j = 0}^{n}\begin{Bmatrix}k \\ j\end{Bmatrix} j! \sum_{i = j}^{n}\binom{i}{j} \\ &= \sum_{j = 0}^{n}\begin{Bmatrix}k \\ j\end{Bmatrix} j! \binom{n + 1}{j + 1} \\ &= \sum_{j = 0}^{n}\begin{Bmatrix}k \\ j\end{Bmatrix} \frac{(n + 1)^{\underline{j + 1}}}{j + 1} \end{align*} \]
今天是一堆博弈論吧。。。(多是開天闢地級別的……由於博弈論除了sg我啥也不會……)
(yyb的博客抄的真開心)
必敗態轉移必定會到必勝態,沒法轉移到另外一個必敗態
必勝態轉移會到至少一個必敗態
AtCoder上有一類題無需過多的博弈論知識,只須要找到必勝態必敗態,很是鍛鍊腦洞能力
找的方法就是按照上面兩種方法分析,一般須要分析遊戲結束時的狀態的性質
取一堆石子有n個,每次至少取1個,最多取\(m\)個
當\((m + 1) | n\)先手必敗,不然先手必勝
就是若是\((m + 1) | n\)的時候先手取什麼,後手均可以跟一步使得總和是\(m + 1\)的倍數,後手必然勝利
不然先手取\(n \% (m + 1)\),轉化到必敗態
有\(n\)堆石子,每堆石子有\(a_{i}\)個,每次能夠選擇一堆取任意多個,不能取的人失敗
全部石子異或的總和若是爲0就是先手必敗,不然先手必勝
證實就是存在一堆石子含有異或和\(x\)的最高位,這個數\(k\)和\(x\)異或後必定小於\(k\),咱們取那麼多石子出來,石子的異或和就從新變爲0
對於一個遊戲的必敗態,\(SG(X) = 0\),不然\(SG(X)\)是當前遊戲能夠到達的局面中未出現過的\(SG\)值的最小值
當全部遊戲異或起來爲0的時候先手必敗,不然先手必勝,證實相似nim遊戲
有n堆石子,每次每人必須取走大於等於1個石子,拿走最後一個石子的人輸
SJ定理
當全部單一遊戲的SG值爲0時遊戲結束,先手必勝的條件是
遊戲的SG值不爲0,存在一個單一遊戲的SG值>1
遊戲的SG值爲0,不存在一個單一遊戲的SG值>1
也是普通的nim遊戲,可是加上了能夠把一堆石子分紅兩堆,不能操做者輸
對於分紅兩堆的遊戲打表後能夠發現是
0 1 2 4 3 5 6 8 7 9 10 12 11
就是除了0之外每四個劃分一下,而後第三個和第四個交換位置
對於每一個沒有結束的任何一個單一遊戲,操做者必須進行一步操做,沒法操做者輸
看似和每一個遊戲的勝負沒有關係了,然而若是先手勝的話,那麼走的次數必定是奇數次,證實這個遊戲會讓後手沒法操做,因此能贏的儘可能贏,效果不會更差
然而對方也是這麼想的,因而咱們想讓對方能贏的局面快點結束
遊戲其實是兩兩獨立的,分開考慮
若是對於一個遊戲,我在本身必勝態,我確定但願這個遊戲儘量的慢點結束,若是我在必敗態,我想讓它儘快結束
因而我在必勝態選擇距離終點最遠的一個必敗態走,在必敗態選擇一個距離終點最近的必勝態走
這樣我一個狀態走到終點的步數經過相似這樣的min-max搜索其實是肯定的
而對於一個必敗態,走的步數是偶數,對於必勝態,走的步數是奇數,對於這樣的遊戲,必勝的條件就是全部點走到終點步數的最大值是一個奇數
不是裸題……可是差很少的樣子?
每次能夠翻轉一些連續的硬幣或者其餘的什麼約束,可是要求最右邊的硬幣必須正面朝上,沒法進行者輸
結論是全部正面朝上的硬幣單一存在時的sg函數的異或和
輪流刪邊,每次保留和根節點連通的塊,不能刪者輸
結論是一個樹的sg值是全部兒子的sg值+1後的異或和
具體證實能夠相似數學概括法那麼證
證實,把每一個兒子當成一棵樹加一條邊,設新加的邊爲\(u,v\),\(u\)是\(v\)的祖先,若斷掉新加的邊,則sg值是0
不然斷\(v\)子樹中的邊,sg函數值爲\([0,sg[v] - 1]\),從小到大取,使得\(v\)爲根遊戲狀態爲0的那條邊,這條邊斷了以後,因爲子游戲中存在一個狀態是斷掉新邊遊戲狀態是0,則這個狀態給\(u\)爲根的貢獻是\(1\)
使得\(v\)爲根貢獻爲1的斷邊狀態,子游戲中斷邊爲0的狀態能夠轉化爲1,再加上斷掉新邊的狀態是0,則這個對\(u\)的貢獻變成了2
以此類推,這種狀況遊戲狀態就是\(sg[v] + 1\)
博弈論這方面,本身推結論是不可能呢,這輩子 都不可能本身推結論的
數學數學又很差,又找不到必勝必敗態……
一打表就可開心了,打表不用動腦子,找規律比用腦子硬想感受好多了,原本就沒有智商,還怎麼作題呢,也只有打打表找找規律,才能勉強維持的了生活的樣子。
\(\binom{n}{m} = \binom{n \% p}{m \% p}\binom{n / p}{m / p}\),其中\(p\)是質數
看到這個能夠考慮數位dp,由於都是n和m在p進制下分解後按位求組合數
若是隨着選的個數\(m\)遞增,答案構成了一個凸函數
而m是固定的,這個時候咱們二分最後一次的斜率,選一個數就減小q,若是這個時候最大值剛好是選了m個則這個斜率就是答案
若是選了大於M個,則斜率須要縮小,不然須要增大
給出平面上\(n\)個點值\((x_{i},y_{i})\),找到一個\(n - 1\)次多項式使得知足這個多項式過這n個點
本質是一種構造
咱們須要拉格朗日基本多項式
\[ \xi_{i}(x) = \prod_{j = 1,j \neq i}^{n}\frac{x - x_{j}}{x_{i} - x_{j}} \]
多項式\(\xi_{i}(x)\)在\(x = x_{i}\)的時候值爲\(1\),在\(x = x_{j}\),\(j \neq i\)的時候是0
而後構造多項式
\(f(x) = \sum_{i = 1} ^{n} y_{i}\xi_{i}(x)\)
在橫座標連續的狀況下,經過\(O(n)\)計算出一個點的值
若是要求出這個多項式,能夠經過\(O(1)\)求出下半部,\(O(n^{2}\log n)\)的複雜度求出上半部分
具體就是\(Solve(l,r)\)計算一個多項式表示沒有乘上\(i \in [l,r]\)的\((x - x_{i})\)的多項式是什麼
而後分治下去
7.12 upd
題意很簡單,就是求\(n\)拆分紅若干個正整數的和有幾種方案
一個簡單的揹包dp是\(O(n^2)\)的
那麼還有一個\(n \log n\)的多項式求逆作法(只寫作法,不寫證實)
利用五邊形數能夠獲得
設\(n\)的分拆數是\(P_{n}\)
五邊形數對於一個相同的\(k\)有兩個,分別是\(\frac{k(3k - 1)}{2}\)和\(\frac{k(3k + 1)}{2}\),前面的係數是\((-1)^{k}\)
\(P_{n} - P_{n - 1} - P_{n - 2} + P_{n - 5} + P_{n - 7}.... = 0\)
而後寫成生成函數
\(P(x) - xP(x) - x^{2}P(x) + x^{5}P(x) +x^{7}P(x)... = x^{0}\)
而後兩邊都除上一個\(P(x)\)
獲得
\(1 - x - x ^{2} + x^{5} + x^{7}... = \frac{1}{P(x)}\)
因而就變成了一個多項式求逆了
7.12 upd end
置換相似矩陣,也是能夠快速冪的
對於一個置換f,若一個染色方案\(s\)通過置換後不變,則\(s\)是\(f\)的不動點,設\(f\)的不動點是\(C(f)\),置換總數爲\(s\),則答案是\(\frac{C(f)}{s}\)
不動點的顏色就是一個置換中染的顏色相同的方案數
若是有\(m\)種顏色,有\(k\)個圈,則一個置換的不動點是\(m^{k}\)
若是有一個線性齊次遞推式(一般不會太長)
拿斐波那契數列舉例吧
\(F_{i} = F_{i - 1} + F_{i - 2}\)
列一個方程
\(x^{2} = x + 1\)
而後解出來兩個根是
\(\frac{1 + \sqrt{5}}{2}\)和\(\frac{1 - \sqrt{5}}{2}\)
而後代入\(F_{1} = 1\),\(F_2 = 1\)能夠獲得
\(A = \frac{\sqrt{5}}{5},B = -\frac{\sqrt{5}}{5}\)
因而通項就變成了
\(f_{n} = \frac{\sqrt{5}}{5}[(\frac{1 + \sqrt{5}}{2})^{n} - (\frac{1 - \sqrt{5}}{2})^n]\)
求一個數列的最短線性遞推式
固然可能一不當心就求出遞推式了,而後就愉快矩陣乘法orn^2多項式取模orO(nlogn)多項式取模了。。。
仍是數列1 2 4 9 20 40 90吧
咱們一開始遞推序列是一個空序列
記爲$R_{0} = {} $,序列的標號到\(0\)
delta是利用真實值和遞推數列算出來的值的差值
\(i = 1\)時,delta = 1,\(R_{0}\) 在 \(1\) 的時候出錯,因此 \(fail[0] = 1\) ,因爲 \(a_{1}\)是一個非0元素,咱們就填上一個0到序列裏,因此\(R_{1} = \{0\}\)
\(i = 2\)時,delta = 2,因而咱們找到\(cnt - 1\)也就是\(R_0\)第一個失敗的地方,1,咱們想利用這個1構造一個遞推數列使得前\(i - 1\)個數都是0,而第\(i\)個數是1,而後\(R_{1}\)加上delta倍的這個遞推數列就能夠了
具體來講此次操做能夠概括成這樣,若\(R_{cnt}\)到了\(i\),則記錄一個\(fail[cnt] = i\)不合法,而後找到\(fail[cnt - 1]\)的位置,構造一個新的遞推序列,把前\(i - fail[cnt - 1] - 1\)個位置都填成0,而後後面加上\(1\),再加上取反的\(-R_{cnt- 1}\)這個數列,這樣可使得第\(i\)個位置有值是\(delta_{fail[cnt - 1]}\),剩下都是0,這個時候就是再乘上一個常數能夠獲得咱們須要的那個序列
(也至關於我把\(R_{cnt - 1}\)的答案經過加0平移了一下……)
接着上面的例子說,這個時候\(fail[1] = 2\),而後構造遞推數列加了0個0,而後加上一個1,再加上取反的\(-R_{0}\),再乘上常數,能夠獲得\(R_{2} = \{2\}\)
\(i = 3\),遞推數列成立,繼續
\(i = 4\),\(fail[2] = 4\),\(delta = 1\),而後構造的數列是\(\{0,1,0\}\),乘上的常數是\(\frac{1}{2}\),因而咱們能夠獲得新的數列是\(R_{3} = \{2,\frac{1}{2},0\}\)
\(i = 5\),仍然成立
\(i = 6\),\(delta = -\frac{9}{2}\),\(fail[3] = 6\),構造的數列是\(\{0,1,-2 \}\),乘上的常數是\(-\frac{9}{2}\)
而後能夠獲得\(R_{4} = \{2,-4,9\}\)
\(i = 7\),\(delta = 9\),\(fail[4] = 7\),構造的數列是\(\{1,-2,-\frac{1}{2},0\}\),乘上的常數是\(-2\)
而後獲得數列\(R_{5} = \{0,0,10,0\}\)
又是今天補昨天的,不過是最後一天了
根據質數的兩個必要條件
$a^{p - 1} \equiv 1 \pmod p $
\(a^{2} \equiv 1 \pmod p\),\(a = 1\)或\(a = -1\)
這兩個條件是必要條件
咱們隨機幾個比p小的質數作a,大概100之內選7個,判錯的機率很小
判的方法是把\(p - 1\)分解成\(2^{k} * s\),的形式,這個時候咱們計算\(a^{s}\),而後把\(a\)不斷翻倍,看最後會不會獲得1,若獲得1看上一次的是否是\(-1\),不然p必定不是質數
咱們在分解一個合數,他的最小質因子必然小於等於\(\sqrt{n}\),根據生日悖論,隨機一個數而後和這個數取gcd能找到這個合數的質因子的隨機次數是\(n^{1/4}\)(事實上,應該設最小質因子是\(p\),複雜度爲\(\sqrt{p}\))
咱們用一個僞隨機數,\(f(x) = x^{2} + c\),不過這個函數沒法處理含有2的質因子,由於它在模4意義下只會生成\(a + 1\)和\(a\),因此咱們只須要暴力去掉2就行了
這個\(c\)能夠在每篩一次的時候遞增,初始值隨機,\(a = b = rand()\),而後\(a\)走一步,\(a = f(a)\),\(b\)走兩步\(b = f(f(b))\),因爲這個函數的特殊性質,它的循環節指望是$O(\sqrt{p}) $
在篩的時候注意判n是質數的狀況,這個能夠用miller_rabin
大概剩下的都歸於奇怪的亂搞
我只記錄一下模擬退火如何以必定機率接受不優的解
設溫度爲\(T\),錯解是\(tmp\),最優的是\(ans\)
那麼能夠用指數函數來計算這個機率\(exp((tmp - ans) / T)\),其中咱們須要\(tmp - ans\)是一個負值,顯然這個負值越大,機率越大,且能夠認爲溫度越大,取錯解的機率越大
這樣咱們就能夠自欺欺人了!
(24天的一輪複習完結了)
(我到底複習了啥啊qwq)