代碼比較長所以直接去LOJ看吧~
魚(計算幾何、向量)
比較套路的內容:枚舉\(D\),對於其他所有點按照\(D\)極角排序,按照極角序枚舉\(A\),這樣垂直於\(AD\)的線也會以極角序旋轉,可以使用雙指針+map的方式維護合法的\(EF\)點對數量。
相對麻煩的是如何對於每個\(AD\)找到合法的\(BC\)的數量。注意到\(BC\)的限制條件很強,要求\(AD\)是\(BC\)的中垂線,且\(BC\)與直線\(AD\)的交點在線段\(AD\)上。
故預處理所有可能的\(BC\),設\(BC\)中點為\(E\),則計算三元組\((\overrightarrow{x},y,z)\),其中向量\(\overrightarrow{x}\)標識斜率,需要滿足向量\(\overrightarrow{x}\)所在直線斜率等於\(BC\)所在直線的斜率、斜率相同直線的\(\overrightarrow{x}\)向量相同;\(y = \overrightarrow{x} ·\overrightarrow{OE}\);\(z= \overrightarrow{x} \times \overrightarrow{OE}\)。
其中\(y\)限制的是\(AD\)在\(BC\)中垂線上:對於任意向量\(\overrightarrow{a},\overrightarrow{b}.\overrightarrow{c}\),如果\(\overrightarrow{b}-\overrightarrow{c} \perp \overrightarrow{a}\),則\(\overrightarrow{a} ·\overrightarrow{b} = \overrightarrow{a} ·\overrightarrow{c}\),證明見點積的幾何意義。所以如果\(AD\)為\(BC\)中垂線,那么\(\overrightarrow{OD} · \overrightarrow{x} = \overrightarrow{OE} · \overrightarrow{x}\)。而我們得到了\(\overrightarrow{AD}\)能比較輕松地得到\(\overrightarrow{x}\)和\(\overrightarrow{OD} · \overrightarrow{x}\),所以可以根據三元組前兩維確定滿足\(AD\)為\(BC\)中垂線的所有\(BC\)。
最后的問題是\(E\)在線段\(AD\)上。根據前面的步驟,\(E\)已經落到直線\(AD\)上,而當某個點\(P\)在直線\(AD\)上向着某一個方向移動時,\(\overrightarrow{x} \times \overrightarrow{OP}\)是單調的,所以如果\(E\)在線段\(AD\)上,則\(\overrightarrow{x} \times \overrightarrow{OE} \in (\overrightarrow{x} \times \overrightarrow{OA} , \overrightarrow{x} \times \overrightarrow{OD})\)。
所以可以預處理上述三元組並排序,對於一個\(AD\)就可以直接二分找到滿足條件的\(BC\)的數量。總復雜度\(O(n^2logn)\),注意常數優化。
JOJO(KMP自動機、主席樹)
暴力就是把一次的插入一個一個插入KMP。這樣插入顯然太慢,所以考慮:將一次插入的一大塊的字符看做一個新的字符(叫做字符段),連續插入\(i\)個\(b\)字符記做字符段\(b^i\)
我們在以新的字符段為基本元素的字符串上做KMP,KMP的next指向的串是當前前綴的一個border。比如\(a^2b^3a^2b^2a^3b^3\),它的next就是0 0 1 0 1 2。
注意到\(next[4]=0\),這是因為\(b^3 \neq b^2\),所以\(a^2b^3\)不能看做前四個字符段構成的字符串的一個border,這意味着因為\(b^2\)后面不可能插入\(b\),所以把\(b^2\)的next指向\(b^3\)的第二個\(b\)是沒有意義的。當然這會使得有答案漏統計,所以要在暴力跳next的過程中統計答案;而\(next[5] = 1\),這是因為加入\(a^3\)時,雖然\(a^3 \neq a^2\),但\(a^2\)是第一個字符段,所以\(a^3\)的后兩個\(a\)可以跟\(a^2\)匹配。這種情況也要額外算答案。
這樣獲得一個比較奇特的KMP。按照這種方法就可以獲得第三個部分分。
對於第二個部分分,我們使用KMP自動機:設\(trans[i][ch]\)表示在\(i\)號位置匹配\(ch\)會匹配到的位置。在第\(i\)個位置插入一個字符,就利用\(trans[i-1]\)找到它的next,\(trans[i] = trans[next_i]\),並將\(trans[i - 1]\)更新。
正解就是把第二個部分分和第三個部分分結合起來。注意到將這兩個部分結合起來會出現以下的問題:
①字符集大小變為\(26 \times 10^4\),\(trans\)開數組難以接受,所以使用可持久化線段樹動態開點維護\(trans\);
②\(trans\)一步到位但是沒法統計答案,這個考慮:把總匹配長度的貢獻分為兩部分,假設\(b^1,b^2,...,b^l\)都被匹配,則一部分是\(\sum\limits_{i=1}^l match_i\),\(match_i\)表示當前插入的\(b^i\)在原串的\(next\)所在字符段之前的所有字符段的總長度,另一部分就是\(\sum\limits_{i=1}^l i\) 。
我們可以用主席樹維護每個點每個字符的\(match_i\)。對於在位置\(p\)插入的一個字符段\(b^i\),假設當前插入\(b^j(j>i)\),且通過跳next跳到\(b^i\)前一個字符,那么\(b^1,b^2,b^3,...,b^i\)都會在這里匹配,即\(\forall x \in [1,i]\ match_x = p-1\),這就是一個區間賦值。而插入\(b^j\),會嘗試匹配\(b^1,b^2,...,b^j\),所以需要求\(\sum\limits_{i=1}^j match_i\),也就是一個前綴求和。這樣我們每一次插入的時候就可以快速求\(match\)並即時維護。求最長匹配長度\(l\)可以維護\(Max[x][i]\)表示從\(x\)匹配字符\(i\)最長可以匹配多少。
③詢問要可持久化,其實這個可持久化可以直接離線,把插入的字符插成一個Trie,然后做帶撤銷的就可以。撤銷就只需要把\(trans\)、\(match\)和\(Max\)還原即可。
多邊形(模擬、組合)
第一問的答案下界是:\(n-3-\)不是多邊形邊界且端點均不是\(n\)的邊的數量,達到的條件是:每一次都能夠找到一個\((a,c)\)旋轉,使得\(d=n\)。
可以使用歸納證明法證明一定可以達到答案下界,即對於任意多邊形都一定存在一個旋轉滿足\(d=n\):
\(n=3\)時顯然成立;\(n \geq 4\)時,若\(\exists i \in[2,n-2] , (i,n) \in e\),則\((i,n)\)一定不會被旋轉,可認為這條邊把當前多邊形分割成兩個小多邊形,一個多邊形為\(1,2,...,i,n\),另一個為\(i+1,i+2,...,n\),對於這兩個多邊形均能達到答案下界,所以當前局面能夠達到答案下界;
如果不存在這樣的點,意味着與\(n\)相連的點只有\(n-1\)與\(1\),所以有邊\((1,n-1)\)。考慮多邊形\(1,2,...,n-1\),對於每條邊,它將多邊形分割成兩個多邊形,保留其中同時存在頂點\(1\)與\(n-1\)的多邊形和在其中的邊,如是做最后一定會剩下三角形\(1,x,n-1\),而且\(x\)唯一,所以存在旋轉\((1,n-1)\)使得旋轉后有邊\((x,n)\),回到上面的情況。所以當前多邊形能夠達到答案下界。
考慮第二問。注意到\((x,n)\)邊,將原多邊形分成了左右兩個多邊形,假設這兩個多邊形內經過一次旋轉之后與\(n\)相連的點為\(y\)和\(z\),那么\(y\)和\(z\)連向\(n\)就會在\(x\)之后。不妨將\(y\)和\(z\)作為\(x\)的左右兒子,那么原來的操作序列就變為了一個森林,第二問就相當於找一個序列滿足對於所有\(x\),\(fa_x\)在\(x\)的前面。
不難發現樹上每個點的貢獻是獨立的,對於點\(x\),它對答案的貢獻為\(\binom{sz_x - 1}{sz_{lson}}\),即它可以把它的兩個后繼的序列在不改變它們內部的順序的情況下隨意組合。整體的答案就是把所有點\(x\)的貢獻乘起來再乘上把整個森林合並起來的方案數
考慮修改。如果修改的是一棵樹的根,那么只有把森林合並起來的部分的貢獻會有變化,否則這一次旋轉對答案的影響就是某一個點的左兒子用\(Splay\)的一次\(rotate\)旋到父親之上(注意這里一定是左兒子,如果選擇的邊對應某個點的右兒子,那么這條邊在\((a,b,c,d)\)四邊形中一定會對應\((b,d)\)邊而不是\((a,c)\)邊),貢獻也只會有這些部分變化。把之前的貢獻除掉、乘上新的貢獻就可以了。
不懂的部分建議自行畫圖理解。
校園旅行(二分圖、BFS)
一個比較顯然的暴力:設\(f_{i,j}\)表示路徑兩端在\(i\)點和\(j\)點時是否存在回文路徑,直接BFS維護轉移,復雜度為\(O(\sum\limits_i \sum\limits_j d_id_j) = O(m^2)\)
看起來似乎沒有更好的方法得到答案,所以考慮優化邊的數量。
設\(ij\)邊表示一端權值為\(i\),一端權值為\(j\)的邊。將所有\(01\)邊加入,原圖會構成若干連通塊,考慮僅保留每個連通塊的一棵生成樹。假設一條路徑中,兩端點中一端最短需要經過\(x\)次\(01\)邊,另一端最短需要經過\(y\)次\(01\)邊(\(x \equiv y \mod 2\),因為可以在\(01\)邊上反復橫跳),那么\(x\)和\(y\)的值可能會增加,增加數量可能不同。但是因為\(01\)邊構成的連通塊一定是一個二分圖,所以在保留一棵生成樹之后,一端一定會需要經過\(x + 2a(a\geq0)\)次\(01\)邊,另一端需要經過\(y+2b(b\geq0)\)次\(01\)邊,而加上\(2\)的倍數不會改變奇偶性,所以原來存在的路徑在只保留一棵生成樹之后仍然存在。
對於\(00\)邊和\(11\)邊我們也按照上述方法去做,但是注意到:如果某一個連通塊內存在奇環,則可以通過繞奇環改變經過邊數的奇偶性,但是生成樹是一個二分圖,所以如果某個連通塊內出現了奇環,給這個連通塊內的一個點加上自環,就和原連通塊等價。
按照上述方式邊數降低為\(O(n)\)級別,BFS復雜度變為\(O(n^2)\)。
白兔之舞(矩陣快速冪、任意模數NTT)
我們要求的就是\((E+Wx)^L\)在\(k\)進制循環卷積意義下的每一項的系數。
因為\(k \mid P-1\),所以\(w_k\)有意義。故先DFT求出點值表示,\(x=w_k^i\)之后就是一個矩陣快速冪,可以\(O(3^3klogL)\)地求出。
然后IDFT求出它的系數表示。IDFT式子是
\(f_i = \frac{1}{k}\sum\limits_{j=0}^{k-1}g_jw^{-ij}\)
注意到除了\(g\)以外其他都是整數,所以\(g_j\)可以是將\(w_k^j\)代入上式之后求得的點值表示矩陣,也可以直接取這個矩陣第\(X\)行第\(Y\)列的值。
然后可以多項式多點求值求\(w^{0},w^{-1},...,w^{-(k-1)}\)的值,但是因為要拆系數FFT所以常數肯定大到跑不過
考慮一個經典的拆\(ij\)的方式:\(ij = \frac{(i+j)^2}{2} - \frac{i^2}{2} - \frac{j^2}{2}\),但是\(i,j\)有可能是奇數,又無法確定\(w\)是否有二次剩余,所以換一種:\(-ij = \binom{j-i}{2} - \binom{j}{2} - \binom{i+1}{2}\),組合數都是整數,這樣上式變為
\(f_i = \frac{1}{kw^\binom{i+1}{2}}\sum\limits_{j=0}^{k-1} \frac{g_j}{w^\binom{j}{2}} w^{\binom{j-i}{2}}\)
用拆系數FFT把后面的求和卷起來就可以求出\(f_i\)。
序列(貪心、可持久化單調棧)
這題結論很多,證明可以看官方題解或者感性理解,比較重要的結論有:
①最優方案一定是將原序列划分為若干等值塊,每一個等值塊的\(B\)相同,且一定是它們權值的平均數。
②貪心的正確性:用一個棧維護等值塊,每一次新加入一個數,先把它自己看做一個等值塊,然后不斷考慮棧頂,如果棧頂的\(B\)比當前加入的等值塊的\(B\)要大就把這兩個塊合並。
③把某個序列划分為左右兩半,那么最優方案中,整個序列的划分點(划分點即滿足\(i\)和\(i+1\)不在同一個等值塊內的\(i\))一定是左右兩半最優划分的划分點的並的子集。這意味着某個序列的最優划分可以看做將這個序列划分為兩半,左邊取最優划分,右邊取最優划分,然后把左邊的一段后綴和右邊的一段前綴合並到一起,並且合並方式唯一。
④對於上面的一段后綴和一段前綴的合並,存在一種先二分右端點、二分右端點的過程中二分左端點進行check的單次\(O(log^2n)\)的做法
那么對於一次修改,可以認為把\(i\)單獨看做一塊,\(1\)到\(i-1\)看做一塊,\(i+1\)到\(n\)看做一塊,將\(i\)的權值修改之后三個塊重新合並,還是可以用上面④的那種二分套二分的方法。至於如何求\(1\)到\(i-1\)和\(i+1\)到\(n\)的最優划分,直接用可持久化單調棧,預處理出所有前綴后綴的最優划分方案即可。復雜度\(O(nlogn+mlog^2n)\)