八月做題筆記
記錄了做到的一些不錯的題,也有模板和知識點。
CF1548C
題意
\(q\) 個詢問,每次給定 \(x\),求 \(\sum\limits_{i=1}^N\dbinom{3i}{x}\)。\(1\leq N\leq 10^6\)。
做法一
設 \(f_{x,k}=\sum\limits_{i=0}^{N-1}\dbinom{3i+k}{x}\),則有
- \(f_{x,0}+f_{x,1}+f_{x,2}=\dbinom{3N}{x+1}\)
- \(f_{x,1}=f_{x,0}+f_{x-1,0}\)
- \(f_{x,2}=f_{x,1}+f_{x-1,1}\)
遞推就能做了。
用到了上指標求和公式(好像叫什麼 Hockey Stick Identity(?):
做法二
設
\[\begin{aligned} \ f_x &= \sum\limits_{i=1}^N\dbinom{3i}{x}\\ &= \sum\limits_{i=1}^N\left(\dbinom{3i-3}{x}+3\dbinom{3i-3}{x-1}+3\dbinom{3i-3}{x-2}+\dbinom{3i-3}{x-3} \right)\\ &=f_x-\dbinom{3N}{x}+3f_{x-1}-3\dbinom{3N}{x-1}+3f_{x-2}-3\dbinom{3N}{x-2}+f_{x-3}-\dbinom{3N}{x-3}\\ &=f_x+3f_{x-1}+3f_{x-2}+f_{x-3}-\dbinom{3N+3}{x} \end{aligned} \]把 \(x-3\)
比方法一的簡潔些。
斐波那契數列通項公式
\[F_n=\dfrac{1}{\sqrt{5}}(\alpha^n-\beta^n) \]其中 \(\alpha=\dfrac{1+\sqrt{5}}{2}, \beta=\dfrac{1-\sqrt{5}}{2}\)。
可以擴域做,即把 \(a+b\sqrt{5},(a,b\in\mathbb{Q})\) 看作廣義的“複數”進行運算。
長鏈剖分
樹上 k 級祖先
各種做法花裡胡哨,這裡說下長剖的做法( \(O(n\log n)-O(1)\)
預處理:
-
對樹進行長鏈剖分,記錄每個點所在鏈的頂點和深度
-
樹上倍增求出每個點的 \(2^n\) 級祖先
-
對於每條鏈,如果其長度為 \(len\),那麼在頂點處記錄頂點向上的 \(len\) 個祖先和向下的 \(len\) 個鏈上的兒子
-
對 \(i\in[1, n]\) 求出在二進位制下的最高位 \(h_i\)
對於每次詢問 \(x\) 的 \(k\) 級祖先:
- 利用倍增陣列先將 \(x\) 跳到 \(x\) 的 \(2^{h_k}\) 級祖先,設剩下還有 \(k^{\prime}\) 級,顯然 \(k^{\prime} < 2^{h_k}\),因此此時 \(x\) 所在的長鏈長度一定 \(\ge 2^{h_k} > k^{\prime}\)。
- 由於長鏈長度 \(> k^{\prime}\),因此可以先將 \(x\) 跳到 \(x\) 所在鏈的頂點,若之後剩下的級數為正,則利用向上的陣列求出答案,否則利用向下的陣列求出答案。
(摘自https://www.luogu.com.cn/blog/xht37/solution-p5903)
HOT-Hotels
經典問題,求樹上兩兩距離相等的三元組個數。
CCPC-Final 2019 G
題意
給定一棵 \(n\) 個節點樹,\(1\) 號節點有一個標記,兩個人輪流移動這個標記到另一個節點,每次移動的距離必須嚴格比上一次對手移動的距離長。求有多少個包含 \(1\) 節點的聯通子圖,使得這個遊戲後手必勝。
\(1\leq n\leq 2\times 10^5\)。
做法
博弈就是紙老虎,不難看出,其實就是求有多少個子圖使得 \(1\) 節點是直徑中點。
先設計這個噁心的 dp。
\(f_{x,j}\) 表示以 \(x\) 為根且最大深度為 \(j\) 的子圖方案數。
轉移:
\[f_{x,j}=\left(\sum\limits_{k\leq j}f_{x,k}^{\prime}\right)\times f_{y,j-1}+f_{x,j}^{\prime}\times\sum\limits_{k<j}f_{y,k} \]其中 \(y\in son(x)\),\(f^{\prime}\) 表示處理到當前兒子之前 \(f\) 的值,這是一個滾動的過程,下文的 \(g^{\prime}\) 同理。
考慮在 \(1\) 節點周圍統計答案,再設計一個更噁心的 dp。
-
\(g_{j,0}\) 表示以 \(1\) 為根且最大深度小於 \(j\) 的子圖方案;
-
\(g_{j,1}\) 表示以 \(1\) 為根且僅有一個兒子中的最大深度為 \(j\) 的子圖方案;
-
\(g_{j,2}\) 表示以 \(1\) 為根且有兩個或兩個以上兒子中的最大深度為 \(j\) 的子圖方案。
轉移:
\[g_{j,2}=g_{j,1}^{\prime}\times f_{y,j-1}+g_{j,2}^{\prime}\times \sum\limits_{k<j}f_{y,k}\\ g_{j,1}=g_{j,0}^{\prime}\times f_{y,j-1}+g_{j,1}\times \sum\limits_{k<j-1}f_{y,k}\\ g_{j,0}=g_{j,0}^{\prime}\times \sum\limits_{k<j-1}f_{y,k} \]觀察這個轉移,我們發現所有轉移都和深度有關,於是想到用長剖優化。處理當前節點 \(x\) 時,繼承 \(x\) 重兒子的資訊,再列舉每個輕兒子所在長鏈,更新 \(x\) 的資訊。式子最後面的那個西格瑪,列舉 \(j\) 的時候維護一個字首和就好了。
不過還有一個問題,根據轉移,處理 \(x\) 時所有的 \(f_x\) 都會被輕兒子更新,但我們又不能列舉到 \(dep_x\)(否則複雜度有變成 \(n^2\) 了),不過再仔細觀察,我們發現當 \(j>dep_y\) 時,後面的那個西格瑪就是一個定值,這就相當於給 \(dep_y<j\leq dep_x\) 的 \(f_{x,j}\) 都乘上一個定值,所以打個懶標記就好了,用到的時候再下傳懶標記,這樣就保證了總的複雜度 \(O(n)\)。
\(g\) 的轉移也就同理了,打懶標記即可。
luogu P1273
\(O(n^2)\) 的樹上揹包
首先把所有節點按後續遍歷重新標號
設 \(f_{i,j}\) 為前 \(i\) 個點,揹包容量為 \(j\) 的最大價值。設 \(siz_i\) 為以 \(i\) 為跟的子樹大小。那麼 \(f_{i,j}\) 就會從 \(f_{i-1,j-1}\) 和 \(f_{i-siz_i,j}\) 轉移過來。
loj 也有這個模板題 https://loj.ac/p/160