棋盤
出題人編出來的做法非常精彩,給出題人點贊!
每次回答詢問都 \(dp\) 一次是 \(\Theta(q^2n)\) 的,不另外贅述了
單獨設一個變量 \(now\) 表示現在維護了 \([l,now],[now,r]\) 的 \(\rm{DP}\) 值,即 \(u_{i,j,k}\) 表示從 \((i,j)\) 出發,到達 \((now,j)\) 的方案數,\(d_{i,j,k}\) 類似,最后一維表示到 \(now\) 行的第幾列
這樣做就可以快速維護:
-
加入一個新的行:\([now,r]\) 的部分發生變化,直接用 \(r-1/r-2\) 行商的值轉移就行了
-
詢問:枚舉 \(now\) 上每個點作為中轉點,由於 \(\rm{DP}\) 過程中沒有環,所以可以直接乘積
-
修改:
-
如果 \(l+1>now\),將 \(now\leftarrow r\),大力重構整個 \(d/u\) 數組
-
否則直接刪去上面的行,實現的時候建議
memset
來避免邊界錯誤
-
不難發現狀態總量是 \(\Theta(qn^2)\) 的,但是每個狀態只會走:在 \(now\) 下面到在 \(now\) 上面一個過程,也就是最多被計算兩次 \(\rm{DP}\) 值
因為馬在條約的過程中可能不經過第 \(now\) 行,那么另外計算一個 \(u_2/d_2\) 表示跳到 \(now+1\) 即可
這里注意如果再出現刪除過程中 \(l>now\) 了需要讓 \(now\leftarrow r-1\) 來保證定義合法性,另外統計答案的時候要斥去兩行之間跳的情況來避免重復統計
構樹
對該問題的解決有非常明顯的刻畫:\(\rm{dp}_ {x,y,z}\) 表示 \(x\) 點為根的子樹里面有 \(y\) 個邊被選擇保留,根節點所在的聯通塊大小為 \(z\) 的對答案的貢獻
這個 \(\rm{DP}\) 配合 \(prufer\) 序列就可以完成轉移:
\(m\) 個大小為 \(\{a_1\dots a_m\}\) 個聯通塊所形成的樹的數量是 \(\prod \limits_ {i=1}^ma_i(\sum a_i)^{m-2}\)
上面結論有個簡單的證明:考察在一個樹的構成方案,每條邊的形成方案是連接的兩個聯通塊大小的乘積
那么所有邊的貢獻相乘則結果為 \(\prod_{i=1}^m siz_i^{deg_i}\)
關注到 \(prufer\) 序列中每個點的出現次數是度數減一,求和之余還要再補充一份
那么將 \(\sum a_i=n\) 分散到每個聯通塊上面統計,樹形 \(\rm{DP}\) 的過程中出現 \((x,t)\) 的邊被斷掉那么就乘 \(n\) 轉移
具體形式相對容易,注意減去已經 \(ban\) 掉的邊在序列里面的貢獻,也就是在斷開之后邊 \((x,t)\) 后 分別包含 \((x),(t)\) 兩個聯通塊連起來的方案要減一
進一步優化考慮觀察最后一維必要性,考慮從一堆有標號點里面選一個的方案數是堆的大小,那么 \(dp_{x,y,0/1}\) 表示是不是選過點了,轉移和上面類似
復雜度和樹上背包一致,為 \(\Theta(n^2)\)
指數做法給了非常多分數讓暴力選手體驗也非常良好
糖
發現 \(s\to t\) 的路徑是必經的,那么樹變成以 \(t\) 為根
對於必經路徑上的每個點,小 A到這個點的時候有“找一個點對應的子樹鑽進去”的決策,那先處理在樹里面的路徑形式:
設 \(dp_x\) 表示在 \(x\) 子樹里面走的最小操作次數,轉移顯然是上來 小 B 找到 \(f_t\) 最大的 \(t\) 斃掉,然后 小 A 鑽到次大子樹里面,小 B 斃掉根節點其它子樹
那么在鏈上的路徑形態也比較容易刻畫,小 A 走到一個子樹里面然后 小 B 封鎖這個點根鏈上所有點的出度,再放 小 A 出來
注意如果在根鏈之前的點上選擇過封鎖邊了,鑽進這個子樹的代價要累加
預處理出來度數前綴和 / \(s\to t\) 所有點非鏈上子樹的代價,考慮二分答案
檢查當前答案是否合法的時候從 \(s\) 到 \(t\) 找所有能鑽的地方,計算 小 A 是不是鑽進去就使次數非法,是則需要提前刪除該子樹
如果必須刪除子樹的操作大於 \(s\) 到該點的距離,那么該 \(mid\) 不合法
時間復雜度 \(\Theta(n\log n)\)
歡樂豆
由於 \(a_i>0\),所以對於沒有修改出邊的點,直接走完全圖上的初始邊就是最優的,不需要進行松弛
為了實現方便,將所有邊修改涉及的點都叫做弱聯通塊里面的點
對於那些存在被修改的邊的點,觀察這種點 \(u\) 到其他點的最短路的可能構成
-
到弱聯通塊里面的點有走出弱聯通塊再返回/直接在弱聯通塊里面走兩種選擇
-
到弱聯通塊外面的點可以花費 \(a_u\) 的代價走到弱聯通塊外面的點 \(v\),再花費 \(a_v\) 的代價隨便走;也可能在弱聯通塊里面亂走,走到一個比較優的 \(w\) 點走出去
注意這里的 \(a_v\) 一定是取的最小的 \(a_v\)
將弱聯通塊里面的點給一個標號,由於朴素堆優化 Dijkstra 復雜度有邊的瓶頸,在完全圖有非常大的缺點,那么考慮線段樹優化尋找從源點開始最小距離點的過程
對於每個弱聯通塊里面的點都進行一個 Dijkstra,初始化葉子上每個點距離為走出再走回的最小距離
每次松弛操作可以轉化為單點取 \(\min\) 和對被修改的兩點之間的區間取 \(\min\) ,是線段樹的基礎操作
在計算弱聯通塊里面的點的最短路的時候維護 \(dis_x+a_x\) 的最小值來表示走出弱聯通塊時候的最短路即可
時間復雜度 \(\Theta(m^2\log m)\)
混亂邪惡
將 \(n\) 變成偶數,即若 \(n\) 不是偶數就在序列里面補一個 \(0\),然后排序
設 \(d_i=a_{2i}-a_{2i-1}\),不難發現 \(\sum d_i\le m-\frac{n}2\le n\),目標是讓 \(\sum d_i=0\)
嘗試推導是否存在任意解,不難發現方法是對 \(d_i\) 的正負號進行調整,同時過程中滿足 \(\forall\ d_i\ge 0\)
嘗試歸納證明這個有解的結論:設 \(n\le 2k\) 時有解,那么現需要觀察 \(n=2k+2\) 時的情況
這時可以找到不為 \(0\) \(\min d_i\) 和 \(\max d_i\) 並將這兩組合並,也就是說得到 \(\min d_i\) 的一組內的 \(c_i\) 一律取反,發現 \(d_i\) 之和的變化量是 \(2\min d_i\)
這樣子 \(n\leftarrow n-1\),變成了原來的子問題,根據歸納假設,原命題成立
回到代碼實現直接能取反就取反就行了,比說的簡單多了
仙人掌
觀察鄰接矩陣行列式的實際含義:找到兩個點匹配,每次貢獻 \(-1\) 的逆序對數
注意每指定兩個數匹配的時候行列式必然加一,而圖為仙人掌的時候將整張環進行匹配的逆序對數為環長減一
這是因為可以將環上的數字重新排序並標號,讓 \(p=\rm{\{len,1,2,\dots,len-1}\}\) 注意到交換兩個點標號之后等價於交換一行的同時交換一列,這樣子逆序對數正負性不變
同時環上匹配的時候可以欽定兩個方向所以貢獻要乘二
梳理貢獻之后是一個套路的仙人掌 \(\rm{DP}\),當然這種東西不容易想出,建出圓方樹后分開討論:
定義實點,也就是原仙人掌上的點有 \(f_{x,0/1}\) 表示這個點是不是被匹配了,匹配指作為 \(p_i\) 出現,對於新建出來的虛點表示 \(f_{x,0/1}\) 表示點雙的根是不是被匹配
由於在現行圓方樹上虛實點交替出現,對於實點的轉移直接考慮是不是在這個點雙被選中,\(f_{x,0}\) 則是所有兒子 \(f_{t,0}\) 的乘積
對於虛點而言,需要一個子 \(dp\),注意在環上第一個點和最后一個點的時候計入環頂被選的方案,同時計算 \(f_{t,0}\) 的乘積來維護環上全選的貢獻
合並實點的時候兩兩一組,做一個子 \(\rm{DP}\) 即可得到答案
乘法
關注到十六進制的后十六位可以使用自然溢出保存,同時可以在 \(\Theta(\log)\) 的時間內計算 \(n!\) 中有幾個因子 \(2\),對 \(4\) 取余后左移回來即可
偶數的部分可以先左移再計算,本質上是一個子問題,那么問題轉化為:\(1\to n\) 中奇數的乘積之和,寫作下式
由於是在 \(\bmod 2^{64}\) 意義下計算,那么選擇 \(2i\) 的項不能超過 \(63\) 個,否則直接溢出
枚舉選擇了多少個 \(2i\),將 \(2\) 因子最后左移加入答案,此時就是計算在 \(n\) 里面選擇 \(m\) 個數字的乘積,求所有選擇方案的和
直接寫出該問題的暴力 \(\rm{Dp}\) 轉移式子發現是 \(2m\) 多項式,直接平方 \(\rm{Lagrange}\) 插值就可以做到 \(\Theta(T\log^{4}m)\),也可以少一個 \(\log\) (但是前者過了后者沒過去是怎么回事呀)
而其實這個問題的答案使用第一類斯特林數可以表示成:
原因是在斯特林數的遞推過程中,增加環大小的那些數字 \(x\)(區別於增加環數量的數字)會貢獻 \(x-1\),將 \(n\leftarrow n+1\) 后就可以得到正確和式
根據實際含義,環大小不為 \(1\) 的環非常少,可以 \(\rm{DP}\) 求出:設 \(dp_{i,j}\) 表示使用 \(i\) 個數字組成 \(j\) 個大小大於 \(i\) 的環,轉移是相對簡單的,枚舉枚舉添加圓排列中的數字個數
實現的時候細節是計算逆元,偶數不存在逆元,奇數的逆元是其 \(2^{63}-1\) 次方,直接使用歐拉定理可以得到
斐波
先記錄比內公式:
記 \(\phi_1 = \frac{1+\sqrt 5}2,\phi_2=\frac{1-\sqrt 5}2\)使用該公式可以將單個 \(f(S)\) 進行展開:
稍加以 \(\rm{GenFunc}\) 思想就能知道 \(\sum\limits_{T\subset S} \phi^{\sum\limits_{x\in T} x}=-1+\prod_{x\in S} (\phi^x+1)\)
也可以組合意義理解:從每個中選一個,也可以不選,最后減去空集情況
至此本題得到極大簡化,那么可以對於每個 \(x\) 計算 \(\phi_1^x,\phi_1^x\phi_2^x\) 的值,因為比內公式本身使用無理數表示有理數,那么無理部分必然消成 \(0\),那么可以不維護 \(\phi_2^x\)(來減小常數因子對程序運行效率的影響)
回到本題,注意題目並不是求一個 \(f(S)\) 的值,而是求一個區間的子區間作為 \(S\) 時的 \(f(S)\) 值之和,這是一個簡單的 \(\rm{DS}\) 問題,可以離線套用古老的序列問題的解法,也可以考慮用如下的線段樹做法:
線段樹每個節點維護 \(\rm{ans,Mult,lsum,rsum}\) 表示答案,區間權值乘積,區間內每個前綴的的乘積和,每個后綴的乘積和,合並信息自推不難
實現的時候可以使用 \(a\sqrt 5+b\) 的形式維護復數值,記得重載乘法和不同復數不同之處
百鴿籠
將對空格子等概論變成隨便找,找到空格子位置為止,此時每列被選中的概率是 \(\frac 1n\),但因為空格子相對於總數量的比例是確定的,兩者相乘得到的結果與前者相同
設 \(G_i(x)=\sum\limits_{i<a_i} \frac{x^i}{i!}\),觀察最后得到的序列的形態(不妨設最終是第 \(k\) 列有剩余格子):
這時候序列中出現的 \(y\neq k\) 的 \(y\) 的數量不小於 \(a_y\) 個,\(k\) 的數量恰好為 \(a_k-1\) 個
如果枚舉最終序列長度不簡潔,但是 \(e\) 的展開式能讓式子大為簡化,寫出序列的 \(\rm{EGF}\) 和用 \(\rm{EGF}\) 表示的答案
這里 \(i\) 枚舉的是除去最后一個人得到的序列長度,上面的 \(i!\) 是多重集排列在使用 \(\rm{EGF}\) 時必要的補充項,分數線下的 \(n^{i+1}\) 是對應的概率,因為序列長度是 \(i+1\),指數含義也由此得到
展開答案,可以表示成 \([e^ax^b]\) 的系數和 \(e^ax^b\) 的乘積的和,其中系數可以通過 \(\rm{DP}\) 得到,設為 \(\lambda\)
推導單獨一個 \([e^ax^b]\) 對答案的貢獻:
后半部分由 \(\sum_{k\ge 0}\binom{m+k}{k}x^k=\frac{1}{(1-x)^{m+1}}\) 可以直接化簡,至此題目得到 \(\Theta(n^6)\) 的做法,正常寫法都可以通過
但是仍然可以通過先做背包求出所有列對應的多項式系數再在單獨求的時候消除貢獻(類回退背包狀物)將復雜度降至 \(\Theta(n^5)\)
游戲
分析兩人策略能得到:
-
對於先手而言,如果他想達到這個石子被/不被自己拿走的目的,在該目的達成/最終失敗之前,他的目的保持不變,具體而言,如果某時想投一面,那么一直投一面
-
對於后手而言,如果先手想達到石子被/不被自己拿走,后手為勝利則需要抗拒先手決策,那么先手想拿走,后手要搶,先手棄的子,后手也不能要
據此定義 \(A_i\) 表示還剩 \(i\) 個石子時先手執先時先手勝利概率,\(B_i\) 表示還剩下 \(i\) 個石子時,后手執先時先手勝率,轉移為:
設每個石子沒有在兩次投硬幣內拿走的概率是 \(R\)
- \(A_i\le B_i\) 時,先手在第 \(i+1\) 個石子的決策應為拿走該石子,此時 \(R=(1-p)(1-q)\)
使用等比數列求和均可以簡單求出,觀察轉移之后的 \(A_i-B_i\),化簡后有 \(pqA_i-pqB_i\ge 0\),成功變成了下面的情況
- \(A_i\ge B_i\) 時,先手在第 \(i+1\) 個石子的決策是放棄該石子,此時 \(R=pq\)
再觀察得到 \(A_i-B_i\le 0\),那么需要用第一種轉移的式子
兩種轉移交替進行,直接使用矩陣快速冪優化即可
Sanrd
不難發現序列的一個 \(\rm{LIS}\) 和一個 \(\rm{LDS}\) 的交點不超過 \(1\) 個,設 \(f_i\) 表示經過 \(i\) 的 \(\rm{LDS}\) 個數,總 \(\rm{LDS}\) 個數為 \(\rm{all}\)
如果一個 \(\rm{LIS}=\{p_1\dots p_k\}\) 滿足 \(\sum_{i=1}^k f_{p_i} =\rm{all}\) 那么其跨過所有 \(\rm{LDS}\)
那么可以在求 \(\rm{LIS}\) 的過程中記錄兩個當前 \(f\) 之和的值不同的前驅,因為后面轉移過程中帶來的增量是相同的,所以必有其一合法
仍然使用數據結構優化這個尋找 \(\rm{LIS}\) 的過程,對於 \(f_i\) 非常大的事實,直接讓其對大質數取模
關注較大方案存在性常用的手段便是對大質數取模,該技巧也可以運用到一類回退背包問題的解決中
如何優雅地送分
觀察 \(2^{f[i]}\) 這一奇怪統計方式,不難發現是一個數集合狀物,那么問題直接轉化為求解下式:
考慮展開 \(\mu^2(i)=\sum\limits_{k^2|i} \mu(k)\),證明考慮實際含義,將 \(\mu\) 函數值不為 \(0\) 的因子放在集合中便可以看做一個完整的容斥起手式
提出 \(k\) 就非常優美了,記 \(S(n)=\sum\limits_{i=1}^n\lfloor \frac ni \rfloor\)
直接整除分塊就行了
ARC124E
傳出球數最小值不為零時可以將所有人的傳球數量減少,因為得到的 \(\{B\}\) 序列不變
觀察原式的實際含義:得到序列后從每個人手上選出一個球的方案數
每個人的球只有兩種來源:自己原來沒有傳出去的球/上一個人傳過來的球。啟示我們記錄球的來源以 \(\rm{DP}\)
下設 \(S_k(n)=\sum\limits_{i=1}^n i^k\)
狀態定義有點奇怪:\(dp_{i,0}\) 表示第 \(i\) 個人從自己處選擇球且不計第 \(i\) 個人選擇方案時前 \(i-1\) 個人的選球方案數,\(dp_{i,1}\) 表示第 \(i\) 個人從前面人選擇球且計入第 \(i\) 個人選球方案時的方案數
轉移分為 \(4\) 種情況:
-
\((i,0)\to (i+1,0)\) 第 \(i\) 個人的選擇方案需要被計入,因為下一個人在自己處選擇,所以沒有 \(a_i\),剩下幾個球就有幾個方案,系數為 \(\sum\limits_{i=1}^{a_i} i=S_1(a_i)\)
-
\((i,0)\to (i+1,1)\) 有兩個人沒有計算,且都在 \(a_i\) 中選擇:\(\sum\limits_{i=1}^{a_i-1} i(a_i-i)=S_1(a_i)a_i-S_2(a_i)\)
-
\((i,1)\to (i+1,0)\) 需要計 \(a_i\) 個球中有幾個傳出,系數是 \(\sum\limits_{i=0}^{a_i}1=1+a_i\)
-
\((i,1)\to (i+1,1)\),和第一個情況類似,系數是 \(\sum\limits_{i=1}^{a_i} i=S_1(a_k)\)
因為是一個環,那么需要在 \(1\) 處統計答案,這時可以枚舉 \(1\) 的決策是在自己處選擇還是在 \(n\) 個人出選擇
注意這樣子統計出來的並不要求傳球數最小為 \(0\) 那么可以再編一個傳球數最小為 \(1\) 的式子寫出來即可
CF1086F
設 \(f_i\) 表示 \(i\) 權值對應點數,對其做前綴和得到 \(g(i)\),觀察其實際含義得到 \(g_i\) 表示在 \(i\) 時刻被標記點數
至此答案可以被表示成 $ T g_T-\sum_{i=0}^{T-1} g_i$
在每個兩個點構成的正方形交之前,點數可以表示成一個二次函數,而在正方形交之后點數擴展量仍逐時間遞增,也是二次函數
所以我們發現 \(g_i\) 是分段二次函數,每個點值都是矩形面積並,可以簡單求出,剩下的任務是分段求出二次函數並求和即可
時間復雜度 \(\Theta(n^3\log n)\)