退役前的做題記錄1.0
CF891E Lust
我們可以考慮差分算出貢獻,那么一次操作的貢獻其實就是\(\prod a_i-\prod a_i'\)。
令最后每個數被減了\(b_i\)次,那么對於一個減的方案,貢獻就是\(\prod a_i-\prod(a_i-b_i)\)。
那么現在的問題就是怎么算出減\(i\)次的貢獻,因為兩個數依次減去\(1\)的方案數是個可重排列,所以我們可以構造指數型生成函數
那么答案就是
令后面那堆東西的乘積\(F(x)=\sum_{i=0}^{\infty} f_ix^i\),
那么最終答案為\(\sum_{i=0}^n\frac{k^{\underline{i}}}{n^i}f_i\)
代碼
CF938F Erasing Substrings
有一個十分直觀的想法,設\(f_{i,s}\)表示目前在原串的第\(i\)位,刪除的集合為\(s\)的最小字典序字符串,那么這樣子是\(O(n^3\log n)\)的。
考慮換個狀態,設\(f_{i,s}\)表示確定了刪除之后的串的前\(i\)位,使用集合為\(s\)的方案數。那么如果兩個狀態\(s,s'\)不存在包含關系,且有\(f_{i,s}<f_{i,s'}\),那么\(s'\)這個狀態就不行。
因為知道了\(i,s\)可以確定下一個保留的字符是什么,取可以最小的轉移,而如果一個狀態有一個子集可以的話這個狀態還是可以,高維前綴和優化下就好了,具體細節詳見代碼。
AGC010F Tree Game
想一下怎么贏下來一局,如果是兩個點那么只能在多的那個點取勝,如果一個點四面八方都是比他權值大的點這個點肯定是個必敗的點,否則就會往一個權值比他小的點跑。
而每跑一步先后手會轉換一下,設\(f_x\)表示先手在\(x\)能否取勝,那么可以從相鄰的權值比他小的轉移上來,如果有一個這樣的點\(v\)滿足\(f_v=0\)那么\(f_x\)就為\(1\),否則是\(0\)。
對每個根跑一遍復雜度\(O(n^2)\)。
代碼
AGC033D Complexity
最暴力的算法就是設\(f[i][j][k][l]\)表示左上角為\((i,j)\),右下角為\((k,l)\)的答案,顯然復雜度爆炸,考慮優化。
注意到答案最多為\(\log (N\times M)\),那么我們可以考慮把答案給計入狀態同時刪去我們原狀態中的一維。
那么可以得出一個新的狀態:\(f[s][i][j][k]\)表示目前我們答案為\(s\),左上、右上角分別為\((i,j),(i,k)\),往下最多能延伸多少長度。
橫着切很好轉移,就是一塊接着上一塊切了的切,即\(f[s][f[s][i][j][k]][j][k]\rightarrow f[s+1][i][j][k]\)。
考慮豎着切一刀,因為可延伸的長度就相當於左右兩邊取\(\min\)而且左右兩邊的\(f\)顯然單調,可以考慮二分左右原本的大小關系發生變化求出,復雜度\(O(n^3\log^2n)\)。
或者可以另設狀態\(g[s][i][j][k]\)表示左上、左下分別為\((j,i),(k,i)\)向右延伸的最大長度是多少,那么這個轉移豎着切是很好處理的,發現這樣的話與\(f\)的轉移正好互補,交替轉移\(f,g\)即可轉移,復雜度\(O(n^3\log n)\)。
CF724E Goods transportation
考慮建圖跑最大流,想辦法怎么優化這個最大流。
想到到最大流\(=\)最小割,可以設\(f[i][j]\)表示目前在第\(i\)個點,\(1-i\)有\(j\)個點和\(S\)連通,轉移很好想,這里不再贅述,注意要滾動數組優化,復雜度\(O(n^2)\)。
[LG3537][POI2012]SZA-Cloakroom
直接暴力背包坑定布星,想辦法怎么優化這個東西。
將所有物品以及詢問按照出現時間的右端點排序,每次按時間從小到大處理物品及詢問,那么可以消除右端點的影響。設\(f_i\)表示\(\sum c=i\)時\(\min b\)最大是多少,然后背包轉移即可。
[LG4229]某位歌姬的故事
首先將所有\(l,r\)離散化,這樣所有的位置就變為\(O(Q)\)級別的。
對於每個位置,我們將所有覆蓋它的區間的權值取個\(\min\),設為\(mn_i\),那么對於一個位置\(i\),只有\(mn_i\)這個權值是有效的。
對於每個\(m\),我們可以把所有\(mn_i=m\)的位置拿出來,對於所有\(m\)分開\(dp\)。
對於每個右端點\(i\),我們記個\(lim_i=\max_i [r==i]l\),設\(f_{i,j}\)表示目前\(dp\)到位置\(i\),上一個取\(m\)的值在哪里的方案數。
轉移分為當前選\(m\)與不選\(m\)兩種:
如果選\(m\)就是所有\(f_{i-1,j},j<i\)轉移到\(f_{i,i}\),
如果不選,就是乘上方案數再把所有\(f_{i,j},j<lim_i\)全部設為\(0\)。
最后把每個顏色的方案數乘起來就好了,復雜度\(O(Q^2)\)。
CF1327F AND Segments
和上題很像的一個題。
顯然對於每個二進制位拆開算然后方案數相乘,假設\(X_i\)的第\(p\)位是\(x_i\)。
同樣的可以對於每個位置求個\(lim_i\),表示\(\max_i [x_i==0]l_i\),以及設出\(f_{i,j}\)表示目前在\(i\),上一個\(0\)的位置。
而對於每個位置,可以差分求出這個位置是否一定要是\(1\)。
碰到一個必須是\(1\)的位置顯然是\(\forall j, f_{i,j}=f_{i-1,j}\)
如果碰到一個是\(0\)的位置的話,轉移就是將\(f_{i,i}\)設為\(f\)的前綴和,\(f_{i,j}=f_{i-1,j},lim_i\leq j<i\),\(f_{i,j}=0,\text{otherwise}\)。
可以數據結構優化\(dp\),也可以記個前綴和數組\(g\)做到對於每一位\(O(n)\)。
CF1286D LCC
第一次發生碰撞坑定是在在數軸上相鄰的兩個栗子間發生的。
預處理出所有的碰撞事件,將他們按照時間排序,依次考慮每一個時間作為第一次碰撞事件的概率。
記事件\(i\)作為第一次碰撞發生的概率為\(\Pr(i)\),不發生的概率為\(\Pr'(i),\)那么\(\Pr(i)=\Pr'(i-1)-\Pr'(i)\)。
現在的問題就是求出所有\(\Pr'(i)\)。
設\(f_{i,0/1,0/1}\)表示第\(i\)個栗子往右/左跑,上一個栗子往右/左跑的概率的和,每次\(\text{ban}\)掉一個事件就是\(\text{ban}\)掉相鄰兩個栗子分別往哪邊跑,也就是\(\text{ban}\)掉一種轉移,考慮將狀態壓成一個矩陣,發現可以滿足矩陣乘法,用線段樹維護矩陣乘積即可。
有一些實現細節詳見代碼。
[十二省聯考2019]皮配
先處理一個考慮一個最暴力的\(dp\),就是設\(f_{i,j,k}\)表示目前到第\(i\)個城市,有\(j\)人選藍隊,有\(k\)人選鴨系的方案數,再對於每個城市求出\(g,i\)表示該城市選\(i\)個鴨系的方案數即可轉移。
再考慮\(k=0\)的情況:可以分別求出\(g_i\)表示選\(i\)個藍隊的方案數,\(f_i\)表示選\(i\)個鴨系的方案數,然后因為不存在限制這兩維互不影響,答案就是\(\sum_{i=S-C1}^{C0}f_i\sum_{j=S-D1}^{D0}g_j\),其中\(S\)為總人數。
注意到\(k\leq 30\),我們可以考慮對於有限制的暴力,然后沒限制的直接乘。
具體方式為:
記\(f_i\)表示城市沒有限制且學校沒有限制有\(i\)人是藍色的方案數,
記\(g_i\)表示學校沒有限制有\(i\)人是鴨系的方案數,
記\(h_{i,j}\)表示學校有限制有\(i\)人是藍色,\(j\)人是鴨系的方案數。
最后答案可以通過枚舉\(h\)的兩維狀態然后再乘上\(f,g\)算出。
這樣是正確的是因為\(f\)算出了所有完全沒限制的學校的顏色方案數,\(g\)算出了有城市限制或沒限制的點的派系方案數,\(h\)算出了有限制的學校的方案數,同時決定了有城市限制的學校的派系方案數,這三者互不影響,卻又能算出所有情況。
至於\(h\)的轉移,可以對於城市挨個轉移,然后分別用兩個數組表示強制顏色是不是藍選出多少鴨系的方案數,dp 完再合並即可,具體實現詳見代碼。
[SNOI2017]遺失的答案
首先所有滿足條件數必是\(G\)的約數,可以知道這些數的個數是不超過\(800\)的。
然后對於所有\(L,G\)的限制就相當於對所有選出的數的質因子次數取\(\min/\max\)。
因為在可能所有數中質因子個數不超過\(\omega =8\),那么我們可以將每一個數對應到一個長度為\(2\omega\)二進制狀態表示第i個數是否卡上界,以及是否卡下界。
對這些狀態統計高維前綴和,我們可以通過容斥得出總方案數。
對於要求包含某個數的方案數,我們可以從高維前綴和中減去包含這個狀態的方案,然后再通過容斥求出合法的方案數,用前面求出的總方案數減去這個方案數即為答案,具體怎么容斥參見代碼。
CF708E Student's Camp
設\(h_{i,l,r}\)表示當前 dp 到第 i 行,當前行剩下\([l,r]\)的概率。
那么轉移就是\(h_{i,l,r}=P(l,r)\sum_{[l,r]\cap[l',r']\neq \phi}f_{i-1,l',r'}\),其中\(P(l,r)\)為剩下\([l,r]\)的概率,易得\(P(l,r)=q_{l-1}\times q_{r-m}\),其中\(q_i={K\choose i}p^i(1-p)^{K-i}\)。
令
\(f_{i,r}=\sum_{l=1}^rh_{i,l,r}\)
\(g_{i,l}=\sum_{r=l}^Mh_{i,l,r}\)
\(F_{i,r}=\sum_{R=1}^rf_{i,R}\)
\(G_{i,l}=\sum_{L=l}^Mg_{i,L}\)
那么有\(h_{i,l,r}=P(l,r)(F_{i-1,M}-F_{i-1,l-1}-G_{i-1,r+1})\)
代入\(f\),有:
最終答案就是\(F_{N,M}\),因為\(F,G\)對稱,所以可以直接用\(F\)推出\(G\)。
[JOISC2020]建築裝飾 4
\(N\leq 2000\)的 dp 比較顯然,而這個 dp 的轉移不好優化,考慮優化狀態。
設\(g_{i,0/1}\)表示到位置\(i\),選了\(A/B\)選\(A\)最多有多少個,\(f_{i,0/1}\)表示到位置\(i\),選了\(A/B\)選\(A\)最少有多少個。
那么如果存在\(op,g_{N,op}\leq N\leq f_{N,op}\)那么就證明有答案,隨便輸出下解即可。
[LG4007]小 Y 和恐怖的奴隸主
設\(f[i][a][b][c]\)表示在第\(i\)輪,除了 boss 有\(a\)個\(1\)血的,\(b\)個\(2\)血的,\(c\)個\(3\)血的概率。
轉移隨便分類討論一波,矩陣快速冪優化下即可,注意矩陣要多開一維記期望,還要卡常。
[CTS2019]氪金手游
首先我們考慮一顆外向樹的情況,令\(x\)的權值為\(v\),\(x\)子樹和為\(w'\),全部的和為\(w\),那么可以等比數列求和算出\(x\)子樹第一次選到\(x\)的概率為\(\frac{v}{w'}\),發現和其他子樹的概率無關,可以背包。
再考慮一條鏈\(1\rightarrow 2\rightarrow 3 \rightarrow ... \rightarrow i\leftarrow i+1 \rightarrow ... \rightarrow n\),這個的概率可以表示為\(\Pr(1\rightarrow i)\times \Pr(i+1\rightarrow n)-\Pr(1\rightarrow n)\),就是這條邊兩邊的概率相乘減去這條邊為正的概率,我們可以把這個東西放到樹上去,就可以容斥了。
而樹上 dp 時我們不用記錄我們有多少條邊是反着的,直接在這條邊向上合並時乘上\(-1\)即可。
[JLOI2016]成績比較
考慮容斥,設\(f(i)\)表示至少\(i\)人被碾壓的方案數,那么有
那么有
令\(g(i)=\sum_{k=1}^{U_i}k^{N-R_i}(U_i-k)^{R_i-1}\)
稍微推下式子:
自然數冪和隨便算算就完事了,總復雜度\(O(n^3)\)。
CF1285F Classical?
考慮確定\(\gcd\),可以調和級數枚舉然后把包含這個約數的所有數都從大到小摳出來,想辦法對於\(\gcd=d\)如何更新答案。
假設我們現在維護了一個類似於單調棧的東西\(s_{1,2...k}\),那么當我們加進一個數\(x\)時我們如何更新呢?可以通過莫比烏斯反演算出這個棧中與\(x\)的\(\gcd\)為\(d\)的數的個數\(t\),然后我們進行彈棧,因為保證了從小到大,所以我們如果\(\gcd=d\)的話就直接更新答案然后彈棧並且\(t\)減一,否則一定滿足當前棧頂的數后面更新的數比當前數\(x\)與前面的數都要小,也可以彈棧,這個過程持續到\(t=0\)。
CF1284E New Year and Castle Construction
隨便選\(5\)個點出來,
記\(x_5\)為這五個點所構成的凸包大小為\(5\)的方案數,
\(x_4\)為這五個點所構成的凸包大小為\(4\)的方案數,
\(x_3\)為這五個點所構成的凸包大小為\(3\)的方案數,
那么答案就是\(x_4+2x_3\)。
而我們有隨便選五個點的方案數是\(x_3+x_4+x_5={n\choose 5}\),乘上\(5\)再減去\(5x_5+4x_4+3x_3\)就是答案。
考慮后面那一坨東西是什么,就是所有五個點凸包的邊數之和。
然后算這個的話就是算每一條邊出現在凸包中的出現次數然后加起來,隨便在一條直線的一半邊選三個點都可以,極角排序后尺取就好了,但是這題卡時間只能用叉積排序。
不等關系
和 [CTS2019]氪金手游 一樣的套路。
假設我們只考慮<
的限制,那么方案數就變為原序列被分成了若干個上升子串的方案數,令每段上升子串的長度為\(len_i\),那么方案數就是可重排列即\(\frac{n!}{\prod len_i}\)。
而總方案數就是:只考慮<
的方案數\(-\)將>
當成<
的方案數,考慮容斥。
設\(f_i\)為長度為\(i\)的前綴除上\(i!\)的結果,\(cnt_i\)表示\(s_1,s_2...s_i\)中>
的數量,那么有
分治NTT優化即可,復雜度\(O(n\log^2 n)\)。
CF1349D Slime and Biscuits
設\(E_x\)為結束時餅干全在\(x\)手中的期望時間,那么答案為\(\sum_{i=1}^nE_i\)。
設\(E'_x\)為游戲結束當且僅當所有餅干均在\(x\)手中的期望時間。
設\(P_x\)為游戲結束時餅干全在\(x\)手中的概率,那么\(\sum_{i=1}^n P_i = 1\)。
設常數\(C\)表示目前餅干全在\(i\)手中,全部轉移到\(j\)手中的期望時間,那么對於所有\(i,j\),這個\(C\)都是相等的。
那么我們有\(E_x=E'_x-\sum_{i\neq x}(C\times P_i+E_i)\)
移項得\(\sum_{i=1}^nE_i=E'_x-\sum_{i\neq x}C\times P_i\),
把所有項相加:\(n\sum_{i=1}^n E_i=n\sum E'_i-C(n-1)\sum P_i\)
由開始所述:\(n\times ans=n\sum E'_i-C(n-1)\)
現在只要把所有餅干移到某個人手中的期望時間,令\(f_i\)表示目前一個人手中有\(i\)個餅干,把所有餅干移到他手上的期望時間,令\(sum\)為所有餅干數目之和,則有轉移:
\( \begin{aligned} \begin{cases} f_i=1+f_{i+1}\frac 1{n-1}+f_i\frac{n-2}{n-1}&i=0\\ f_i=1+f_{i+1}\frac {sum-i}{sum} \frac 1{n-1}+f_{i-1}\frac i{sum}+f_i \frac{sum-i}{sum} \frac{n-2}{n-1}&i\in (0,sum)\\ f_i=0&i=sum \end{cases} \end{aligned} \)
用樹上高斯消元的 trick ,設\(f_i=Af_{i+1}+B_i\),推下式子把\(A_i,B_i\)求出來即可,這里不再贅述。
[CTS2019]隨機立方體
設\(f_i\)表示至少有\(i\)個極大值的概率,\(g_i\)表示恰好有\(i\)個極大值的概率,令\(lim=\min(l,m,n)\)那么
二項式反演得,
所以我們現在要想辦法求出\(f_i\)。
首先考慮我們按順序加入\(i\)個極大值的坐標的方案數,就是\(n^{\underline i}m^{\underline i}l^{\underline i}\)。
然后你需要求出在已選出的坐標控制范圍的並內,放入數字使得每個選定坐標均為自己控制范圍內最大值的概率。
因為我們之前是考慮過順序的,所以我們可以改變一下放入的限制,即由自己控制范圍內的最大值變為目前剩余空間中的最大值,那么每次放入后,只被當前最大值控制的區域就可以刪掉了,就由\(i\)個點轉化為了一個只有\(i-1\)個點的子問題了。
設\(S_i=nml-(n-i)(m-i)(l-i)\),那么
后面那坨東西可以用求組合數的方法正推一遍,倒推一遍求出,就可以做到\(O(n)\)了。
[JOISC 2020 Day2] 遺跡
考慮從后往前做這個問題,先將序列的最后一個數放進來,那么這個數在之后的操作中都不會改變了,然后我們加進第二個數,如果這個數和最后一個數沖突的話,這個數最終會減一,以此類推,每放進來一個數,如果它和之前的每個數的最終狀態相沖突的話,它會一直減減直到它減到一個沒出現的數字作為它的最終狀態。
那么我們有個狀壓dp,設\(f_{i,s}\)表示做完\(i\sim n\),最終狀態出現了數集\(s\)的方案數,那么每次放入一個數可以對於一段連續的\(1\)進行轉移,如果放到了前綴\(1\)就意味着這個數沒出現在最終狀態。而兩個相同的數我們不好確定它加入的順序,所以我們認為相同高度的兩個石柱本質不同,最后將答案除去\(2^n\)。
考慮優化這個狀態,設\(f_{i,j}\)表示做完\(i\sim n\),最終狀態出現的數集\(s\)的前綴\(1\)的長度為\(j\)的方案數,這個地方的轉移比較巧妙:
假設目前我們放入一個數\(x\),如果\(x>j+1\),我們先不管它,直接繼承前面的值。
如果\(x<j+1\),那么它沒出現在最終序列里,可以算出有多少個這樣的數然后轉移。
最后是\(x=j+1\)的情況,我們考慮加入這個數后前綴\(1\)的長度增加了\(k\),轉移的話就是選擇前面被保留的數(共\(cnt\)個)中選擇一些放在\(x\)后的\(k-1\)個數中,有\({cnt-j\choose k-1}\)中選法,而這個數\(x\)的選擇也有\(k+1\)種,有轉移\(f_{i,j+k}\leftarrow f_{i,j}\times(k+1)\times {cnt-j\choose k-1}\times g_{k-1}\),其中\(g_{k-1}\)表示后面\(k-1\)個數放進來的方案數,最后的步驟就是怎么求它。
設\(h_{i,j}\)表示\(i\)中高度,占了\(j\)個位置的方案數,枚舉每次選\(0,1,2\)個這個數字\(i\),那么有
\(h_{i,j}=h_{i-1,j}+h_{i-1,j-1}\times2j+h_{i-1,j-2}\times j(j-1)\),最后\(g_k就等於h_{k,k}\),這題就做完了,復雜度\(O(n^3)\)。
[2018 集訓隊互測 Day 5]小 H 愛染色
欽定\(i\)為編號最小的球,那么方案數為\({n-i\choose m}^2-{n-i-1\choose m}^2\)。
令\(G(i)={i\choose m}^2\)
答案就是\(\sum_{i=0}^{n-m}F(i)(G(n-i)-G(n-i-1))\),所以把\(H(i)=\sum_{i=0}^{n-m}F(i)G(n-i)\)求出來就好了。
考慮到\(F\)是個\(m\)次多項式,\(G\)是一個\(m^2\)次多項式,\(H\)是把他們兩個乘起來再加起來也就是\(3m+1\)次多項式,所以可以考慮把\(H\)的前\(m\)項求出來然后拉格朗日插值。
注意到\(F\)只給了你前\(m\)項所以要用這題的方法插出前\(3m+1\)項的值,然后\(\mathcal {NTT}\)把\(F,G\)卷起來就可以了,要注意優化常數,如果\(G\)某些前后綴是\(0\)那么\(\mathcal{NTT}\)就沒必要開那么長。
復雜度\(O(m\log m)\)。
CF603E Pastoral Oddities
發現當有方案當且僅當所有聯通塊大小均為偶數。
證明的話就是一個聯通塊所有點的總度數為偶數,如果聯通塊大小為奇數的話奇數個點的度數和一定為奇數所以不滿足。
考慮用\(lct\)維護聯通塊,維護的東西是虛子樹的\(size\)以及鏈上最大值以及最大值所在節點編號。
如果合並之前未被合並的聯通塊直接用虛子樹的\(size\)維護目前還有多少個大小為奇數的聯通塊,否則則找到最長的那條邊看要不要刪掉。最后在全局用一個數據結構維護所有的邊,按邊權從大到小排序后依次取出判斷能不能斷開即可,細節詳見代碼。
[NOI2019]序列
考慮如圖所示的費用流連邊,其中\(C\rightarrow D\)的容量為\(K-L\)其余都為\(1\),\(S\rightarrow A_1,A_2...A_n\)費用為\(a_i\),\(B_1,B_2...B_n\rightarrow T\)費用為\(b_i\)其余都為\(0\)。
在這個圖上限流為\(K\)跑一下結果顯然是對的,考慮模擬這個費用流的過程以降低復雜度。
如果\(C\rightarrow D\)之間有邊的話我們會先跑這條邊,因為這樣子可以任意選擇\(A,B\)結果顯然更優。
考慮當\(CD\)滿流時我們如何增廣:
\(\text{Case1: }\)選一條\(B_i\)已匹配的最大的\(A_i\),流\(S\rightarrow A_i\rightarrow B_i\rightarrow T\),那么\(D\)出來會少一條流量,需要選一個最大的\(B\)出來保持流量平衡
\(\text{Case2: }\)選一條\(A_i\)已匹配的最大的\(B_i\),流\(S\rightarrow A_i\rightarrow B_i\rightarrow T\),那么\(C\)進來會少一條流量,需要選一個最大的\(A\)出來保持流量平衡
\(\text{Case3: }\)選一條均未匹配過的和最大的\(A_i+B_i\),直接流過去即可
注意到\(\text{Case 1,2}\)可能會使\(CD\)流量減一,要優先流能使其減一的\(\text{Case}\)。
綜上所述,我們應用\(5\)個堆維護我們所需信息。
CF671C Ultimate Weirdness of an Array
注意到如果我們枚舉\(f\)的取值的話是不好算的,所以我們可以算\(f\leq i\)的方案數\(h_i\)然后用\(h_i-h_{i-1}\)可以算出\(f\)為\(i\)的方案數,答案即為\(\sum_{i=1}^{V} i\times (h_i-h_{i-1})\)。
對於每個位置\(i\)我們記\(nxt_i\)表示以\(i\)為左端點\(l\),右端點\(r\geq nxt_i\)且保證\(f(l,r)\leq i\)的最小的\(r\),那么\(h_i=\sum_{j=1}^n n-nxt_j+1\),最開始\(nxt_i=i\)。
將\(d\)從大往小掃,把所有是\(d\)的倍數的位置摳出來,記為\(x_1,x_2...x_m\),要保證\(f(l,r)\leq d-1\)就只能保留一個至多位置,可以對於\(i\in[1,x_1]\),\(nxt_i\)對\(x_{m-1}\)取\(\max\),\(i\in(x_1,x_2]\)對\(x_m\)取\(\max\),\(i\in(x_2,x_3]\),對\(n+1\)取\(\max\),然后求整體的\(\sum nxt\)即可,因為\(nxt\)單調所以不需要用吉利線段樹,用 普通線段樹區間賦值\(\text{or}\;set\) 維護即可。
CF1270H Number of Components
發現所有聯通塊都是一段區間,可以感性理解一下,這里不作證明。
那么一段前綴和一段相鄰的后綴如果被分為兩個聯通塊,就意味着前綴\(\max\)小於后綴\(\min\)。
那么如果我們枚舉\(v\),把\(> v\)的數設為\(1\),\(\leq v\)的數設為\(0\),如果這個序列呈現出前綴全部是\(1\)后綴全部是\(0\),就意味着聯通塊數目需要加上\(1\)。
考慮維護對於每個\(v\)的\(0/1\)交界的個數,那么需要將位於原序列位置\(a_0\)的數設為\(\infty\),\(a_{n+1}\)的數設為\(0\),否則會出現前后綴\(01\)反過來的情況。
對於相鄰的數\(a_i,a_{i+1}\),會對\([\min(a_i,a_{i+1}),\max(a_i,a_{i+1}))\)加上\(1\)的貢獻,用線段樹維護值\(v\)的\(01\)交界數最小值以及最小值出現次數即可,注意必須要保證線段樹中的\(v\)必須在原序列中出現過才能夠計算貢獻。
[JOISC 2020 Day1]掃除
離線。
把每個掃除的操作當做一個點,那么每次所要查詢的就是從一個點插入到這次查詢經過這段區間后這個點會變為多少,我們考慮將這段區間打在線段樹上,那么這段操作就對應了\(\log\)段小區間。
如果只有向一邊的操作,那么操作間是互不影響的。
而對於一個向右的長度為\(h\)掃除以及在它之前的向上的長度為\(x\)的掃除,這個\(h\)實際上只會影響到高度\(\leq h\)且橫坐標在\([x+1,n-h]\)的點,可以先預處理出這樣的操作,然后對於每個區間中的查詢,對\(h\)排序單調指針掃然后橫坐標用線段樹維護。
細節建議參照代碼,復雜度兩只\(\log\)。
[JOISC 2020 Day2]有趣的 Joitter 交友
考慮將互相關注的點縮成一個聯通塊,然后維護這個聯通塊的\(size\)和單向邊進來的點,和這個聯通塊出去的點,那么算答案是容易的。
合並時也不是很難做,但是如果發生連鎖反應要遞歸處理。
[JOISC 2020 Day3]星座 3
\(\mathsf{\color{black}{M}\color{red}{\_sea}}\)題解講得很清楚,就直接蒯他的了/kel:
考慮一個貪心。從下往上掃,同時每個位置維護一下它下方保留了的不能與它共存的權值和,對於每顆星星留一個權值大的即可。
考慮每顆星星上方不能與它共存的星星的范圍,顯然是往左、往右走到第一棟比它高的大樓的范圍。
用並查集維護每個點往左、往右最遠能走到哪里,然后區間加一下就好了。
[JOISC 2020 Day4]首都城市
考慮把每個顏色的點摳出來向他們路徑上的其他的顏色連邊,邊\(x\rightarrow y\)表示如果\(x\)要作為首都則必須合並\(y\),連完邊后縮點求出的最小的無出度的點的\(size\)即為答案。
這樣子連邊是\(n^2\)的,用\(\mathcal{ST}\)表優化下就是一個\(\log\)的了。
[JOISC 2020 Day4]治療計划
考慮兩個區間\([L_i,R_i],[L_j,R_j](R_i\geq L_j)\)是否能拼成一個區間的情況就是\(R_i-L_j+1\geq |T_i-T_j|\)。
所有區間按\(T\)排序,把絕對值拆開后用線段樹維護絕對值為正負的兩種情況,考慮以與\(1\)相連的區間跑最短路直到與\(n\)相連,\(dijkstra\)時用線段樹找點,因為第一次更新時坑定最優所以當找到這個點時直接把這個點從線段樹上刪掉就保證了復雜度。
[十二省聯考 2019]字符串問題
考慮怎么判斷是不是無窮,可以先從\(A\)按照支配順序向\(B\)連邊,然后\(B\)如果是\(A\)中某個串的子串就連回\(A\),看下有沒有環就行了。發現如果是求最長的話就是在這個無環的 DAG 上拓撲排序。
考慮后綴排序后優化連邊,直接用普通的線段樹優化連邊會有問題,因為\(B\)連向\(A\)的邊可能有\(|B_j|\geq |A_i|\),但是這樣還是有\(80\) pts。發現可以按照\(A,B\)的長度從大到小排序依次加入時用主席樹優化連邊就可以解決這個問題了。
CF1063F String Journey
這\(k\)個串的長度最優時一定是\(k,k-1...2,1\),否則一定可以構造成這種情況。
設\(f_i\)表示\(i\sim n\)以\(i\)結尾的最優答案,那么有\(f_{i}-1\leq f_{i+1}\Leftrightarrow f_i\leq f_{i+1}+1\),所以從\(i+1\rightarrow i\)時,我們可以枚舉\(f_i\)的取值,這樣子均攤下來復雜度是正確的。
現在的問題就是判斷\(f_i\)取某個值\(k\)是否可行,如果\(f_i=k\)可行的話,則必須要滿足條件:
存在\(j\geq i+k\),\(f_j\geq k-1\),且\(lcp(suf_i,suf_j)\geq k-1\; \text{or}\;lcp(suf_{i+1},suf_j)\),因為無論怎樣\(i+k\)都是單調不升的,所以可以拿單調指針掃,而\(lcp\)后綴排序之后對應一段區間,拿個線段樹維護\(f\)的區間即可。
[集訓隊作業2018]喂鴿子
[SNOI2019]通信
大概像這樣建個邊:
然后跑費用流(容量和流量未標出)
考慮如何優化連邊:
考慮CDQ分治,然后考慮右邊區間向左邊區間連邊,將左邊的點按照權值大小排好序之后前綴優化連邊就好了。
[JSOI2019]絕地反擊
以前寫過一遍了
這里提供兩種方法:
方法一:
是我自己想到的,對於圓上點的排列,假設所有點均由正方向旋轉度數\(\alpha\),那么最優解函數\(f(\alpha)\)一定為一個單峰函數。
三分\(\alpha\)后再二分時間\(t\),將到達時間\(\leq mid\)的我方艦隊向敵方母艦連邊,跑二分圖匹配看是否有完美匹配即可。
(別人寫的能過,我不知道為什么自己寫的過不了/kk
代碼
方法二:
二分時間\(t\),那么對於每艘戰艦在圓弧上的交點至多只有\(2\)個,而對於旋轉,可以發現本質不同的轉法一定是有一個點轉到了這\(2n\)個交點中的其中一個。
我們將這\(2n\)個轉角極角排序(這\(2n\)個點可用余弦定理算出),則每次改變轉角最多加入或刪除一組匹配,手動模擬退流即可,復雜度\(O(二分圖匹配\times\log n)\)。
代碼
[GXOI/GZOI2019]旅行者
正反圖各跑一遍最短路,然后枚舉邊計算答案即可。
代碼
[NOI2016]網格
顯然答案最大為\(2\),那么對於這個圖我們只有\(-1,0,1,2\)四種情況,考慮依次判斷。
對於\(-1\),如果只有一個空位或者有兩個空位且空位相鄰則滿足。
對於\(0\),可以選取每個已有的點周圍的八連通的空位然后判斷這些空位組成的四連通塊是否連通即可,這里我選取的是周圍的\(24\)個點原因下面講。
對於\(1\),就是判斷我們所選取出的點中是否存在割點,但是如果我們僅僅選出八連通塊,會出現這樣的情況導致誤判:
.00
.X1
.00
所以我們選出\(5\times 5\)的范圍,而且只有割點是周圍的八個點才行,要不然會出現這樣子的情況:
100..
000..
00X00
..000
..001
注意特判\(n=1\ \text{or}\ m=1\)
不滿足以上情況就是\(-2\)。
代碼細節有點多。
代碼
[SDOI2017]樹點塗色
[清華集訓2014]主旋律
這種題目考慮 容斥+狀壓。
設\(f_i\)表示點集\(i\)所構成強連通子圖的方案數,那么可以拿\(2^{|E_i|}\)減去不滿足要求的,其中\(E_i\)表示\(i\)中的邊數。
考慮枚舉入度為\(0\)的強連通子圖的聯通塊,但是無法保證所枚舉的聯通塊一定構成一個強連通分量,所以考慮進一步容斥。
發現容斥系數只與所枚舉的的聯通塊所構成的強連通分量的個數有關,因此可以設\(g_i\)表示點集\(i\),構成奇數個強連通分量的方案數\(-\)構成偶數個強連通分量的方案數。
應為每次新加進一個強連通分量容斥系數就會乘上\(-1\),那么有轉移\(g_i=-\sum_{j\subset i}f_j\cdot g_{i-j}\),注意\(g\)不包含只含有一個強連通分量的情況,以便下面的轉移。
再枚舉某一個入度為\(0\)的聯通塊,那么又可以得到\(f_i=2^{|E_i|}-\sum_{j\subset i}g_j\cdot 2^{|E_i|-|E_j|}\)。
最后再將\(f_i\)算入\(g_i\)即可,答案就是\(f_{全集}\)。
代碼
[NOI2018]歸程
跑一遍\(1\)到每個點的最短路,然后按照海拔從小到大建克魯斯卡爾重構樹,倍增找到在克魯斯卡爾重構樹上一個點可以跳到的最淺的點然后查下子樹最短路的最小值即可。
代碼
[NOI2017]游戲
沒有x
我們可以直接\(\text{2-sat}\)輸出方案,有x
時只需枚舉第\(i\)種賽道不適合A車或B車,因為這樣子就可以包含不適合C車的情況了,然后直接\(2^d\)爆搜一下就好了,具體的連邊方式什么的直接看代碼就好了。
代碼
[雅禮集訓2018]仙人掌
先考慮一棵樹的情況,令\(f_{x,0/1}\)表示考慮\(x\)與其子節點的邊,\(x\)的出邊是(1)否(0)已滿的方案數。
那么轉移是個背包,其中對於\(v\in son_x\)如果增加\(x\)的一條出邊的方案數是\(f_{v,0}+f_{v,1}\)否則是\(f_{v,0}\),那么這個背包用\(\mathcal {NTT}\)轉移一下就可以做到\(O(n\log ^2 n)\)。
仙人掌的情況我們考慮圓方樹上的 dp,令\(f_{x,0/1/2}\),具體表示的是什么我們分情況討論。
如果\(x\)是一個圓點,且它的父親也是圓點,\(f_{x,0/1}\)表示它的父親節點與它之間的邊是否是指向\(x\)的方案數。
如果\(x\)是一個方點,且它的父親是圓點,\(f_{x,0/1/2}\)表示這個環的最上面的兩條邊(就是與\(fa\)直接相連的那兩條),不指向fa的方案數。
如果\(x\)是一個圓點,且它的父親是方點,\(f_{x,0/1/2}\)表示的就是它所在的環上與它直接相鄰的兩條邊,指向它自己的邊的方案數。
轉移的話如果\(x\)是圓點,可以和樹一樣NTT,如果是方點的話,枚舉環中一條邊的方向即可轉移,具體細節詳見代碼。
代碼
[雅禮集訓2018]Magic
考慮容斥,設\(f_i\)表示恰好\(i\)的答案,\(g_i\)表示至少包含\(i\)個魔術對的序列數。則:
我們考慮將所有球分配一個標號,那么最后的答案要乘上一個\(\prod \frac 1{a_i}\)。
設\(R_{i,j}\)表示前\(i\)種球至少有\(j\)對的方案數,\(h_{i,j}\)表示第\(i\)種球至少有\(j\)對的方案數。
那么最后\(R\)就是所有\(h\)的卷積,考慮怎么求\(h\)。
\(h_{i,j}\)就是從\(a_i\)個求中選出\(a_i-j\)個,然后剩下\(j\)個球依次接到之前放的某個球的前面,方案數為
可以分治NTT將所有\(h\)卷起來得到\(R\),
注意一下最后的\(R_{m,i}\)並不是\(g_i\),因為根據我們剛才的轉移,剩下的\(n-i\)個球可以隨便選出,所以還要乘上\((n-i)!\)。
代碼
[集訓隊互測2019]國際象棋
最裸的高斯消元是\(O(n^3m^3)\)的。
考慮將第一、二行和第一列的所有元素拉出來做主元,那么我們從上至下、從左至右處理每一個點時,它的期望只有\(4\)號位移的點你是沒有表示出來的,所以我們可以通過這個點的期望減去其他\(7\)個點算出,最后棋盤外對應有幾個\(0\)的地方拉出來消元就可以把這些主元全解出來了。
代碼