一句話題解3


目錄


CF Deltix Round, Spring 2021 (open for everyone, rated, Div. 1 + Div. 2)

A:如果一次沒有變化以后都不用做,一共最多變化\(n\)次,所以暴力做\(\min(n,m)\)輪即可。

B:發現可以兩個兩個分為一組搞,試一下就出來了。

C:我嘗試了半天的做法:每次找到最后一個位置\(x\),滿足\([x-a_x+1,x]\)\([1,a_x]\),然后把它作為\(x-a_x\)的子目錄。題解做法:維護個棧,棧中記下每一層是第幾個。如果遇到\(1\)就入棧,如果大於\(1\)就彈棧直到找到所存第幾個是小於當前的。

D:隨機一個人,有一半的概率他在解中被考慮到。然后取出與這個人有關的顏色,用FWT做一下即可。隨機枚舉大概50次。(PS:CF的time(0)是不變的,所以別人可以通過對着隨機種子hack。為了防止被hack,可以利用評測機本身運行時間的波動性,借助clock()來增加隨機種子的不穩定性,具體見這份代碼

E:考慮要么加一個0,要么加(k-1)個0和1個1。第一個1前面的0長度需要枚舉一下。列出式子稍微化簡一下即可。

G:統計一下作為答案的區間的個數的總和,發現是\(O(n\lg n)\),只要能精准地找到作為答案的區間就好了。對於每個長度分別做。設\(qry(l,r)\)表示問某區間內的答案,找到最小的\(i\)滿足\([L_i,R_i]\in [l,r]\),然后分成\(qry(l,L_i-1)\)\(qry(R_i+1,r)\)。用二維數據結構維護即可哇這是我第一次打二維數據結構誒。時間\(O(n\lg^3 n+m\lg^2 n)\)


7102. 【2021.6.3 NOI模擬】集合

從小到大排序,然后跑A*。每次取出平均值最小的,然后擴展(兄弟和兒子)。

因為每次擴展只會擴大,所以沒有問題。


7103. 【2021.6.3 NOI模擬】匹配(口胡)

把匹配方案看成個排列,然后發現其實答案就是行列式,每個位置一開始是個一次多項式。

直接算是\(O(\frac{n^5}{\omega})\)的時間。另一種做法:找\(\frac{n}{B}\)個最高次為\(B\)的不可約多項式,在模每個不可約多項式意義下做高斯消元,最后中國剩余定理合並。預處理出值域(\(2^B\))內的所有值之間的乘法運算和求逆運算,於是就可以迅速地做高斯消元了。

(沒有想細節)


7104. 【2021.6.3 NOI模擬】鍛煉

如果沒有顏色的限制,可以有這樣的貪心:找到最小的右端點,在這個位置搞一次,順便將其它經過這里的區間刪掉。

正確性:這個右端點往左的位置,包含它的集合不會擴張。

現在有了顏色的限制。如果同顏色的區間的右端點不等,同樣也可以類似地做,只是在當前位置放的時候,相同顏色的區間中,選擇右端點最小的。

如果同顏色的區間的右端點相等,將左端點最大的區間右端點保持不變,其它區間右端點往左縮一格。調整直到同顏色區間的右端點不等,然后就可以用上面的方法做了。

模擬上述過程即可。時間\(O(n\lg n)\)


7107. 【2021.6.5 NOI模擬】超高校級的絕望

題目大意是假的

競賽圖縮點之后是一條鏈從前往后連邊。預處理成每個塊內部的貢獻,然后\(O(3^n)\)子集卷積。

計算塊內部貢獻,可以DP欽定一條哈密頓回路,其它的邊怎么優怎么連。時間\(O(2^n n^3)\)

(注意不存在大小為\(2\)的強聯通分量……)


7106. 【2021.6.5 NOI模擬】傑尼羅斯 艾歐

一開始欽定點權為0,邊權為1。定義價值為點權+鄰邊邊權。現在考慮增量搞,考慮完\(1..i-1\),現在加入\(i\),要求不改變\(1..i-1\)的價值。設\(T\)表示\(1..i-1\)中和\(i\)相連的點的集合。

首先對\(T\)中點權為0的:把點權+1,邊權-1。於是\(T\)中所有點點權為1。

現在對每個T中的點都可以做這樣的操作:點權-1,邊權+1,它價值不變,\(i\)價值加一。

由於\(T\)中至多有\(|T|\)種不同的價值,而經過這樣的操作有\(|T|+1\)種取值,所以一定可以取到。

采取合適的實現可以做到\(O(n+m)\)


【UR #4】元旦三俠的游戲

\(b\ge 2\)的時候,狀態是很少的,可以全部處理出來。

\(b=1\)的時候,處理出\(a\le \sqrt n\)的,后面的可以直接算出來。


【UR #4】元旦激光炮

假設三個數組長度為\(k\)(不夠的補\(\infty\)),下標從1開始。

\(l=\lfloor\frac{k}{3}\rfloor\),然后比較\(a_l,b_l,c_l\)。然后取出最小的,不妨設是\(a_l\)。易證\(a_{1..l}\)都小於第\(k\)小。於是將它們扔掉,並\(k\leftarrow k-l\)。當\(k\le 2\)的時候直接暴力。次數大概是\(3\log_\frac{3}{2} k+6\)。可以通過。

題解中\(c_n=0\)的部分分也很有趣:考慮兩個長度為\(k\)的數組求中位數,不妨設\(k\)為偶數,\(i=\lfloor\frac{k}{2}\rfloor,j=k-i\)。比較\(a_i,b_j\),如果\(a_i<b_j\),則對於\(a_{1..i}\)來說,\(a_{i+1..k}\)\(b_{j..k}\)大於它們,有\(n+1\)個數;對於\(b_{j+1..k}\)來說,\(a_{1..i}\)\(b_{1..j}\)小於它們,有\(n\)個數。於是將\(a_{1..i},b_{j+1..k}\)除去,中位數不會改變。於是每次砍半,次數\(2\lg k\)

(實際上在\(c_n=0\)時,根據\(kth=\min_x \max(a_x,b_{k-x})\)得,可以二分出最大的\(x\)滿足\(a_x<b_{k-x}\),然后比一比\(b_{k-x}\)\(a_{x+1}\)即可)


【UR #4】追擊聖誕老人(口胡)

求前\(k\)小肯定是A_star。普通的A_star實現是每次找到權值最小的狀態,擴展它的第一個兒子和下一個兄弟。

我的想法:直接維護第幾大。不用腦子的想法就建個根到節點的主席樹,於是時間\(n\lg n\),空間\(3n\lg n\),不夠;想了半天想了個括號序,左括號加入右括號刪除,線段樹維護,每個區間中分別維護加入和刪除的數的有序序列(調整一下數的大小使其嚴格有序)。二分第幾大是多少,然后在線段樹上對應的區間上二分。空間\(2n\lg n\)也許可以,然而時間\(n\lg^2 n\)

題解:A_star並不一定嚴格只找下一個兄弟,可以限制出邊的集合類似分治地去搞。用人話說:狀態記\((w,x,Suc)\)表示權值為\(w\),當前在點\(x\),出邊的集合為\(Suc\)

考慮將\(Suc\)變成\(Suc_l\bigcup Suc_r\bigcup y\)\((w+\dots,y,\dots),(w+\dots,\min Suc_l,Suc_l),(w+\dots,\min Suc_r,Suc_r)\)。暴力做法可以直接求出\(Suc\)(以指向堆的節點的指針的形式),用可持久化可並堆+倍增來搞。

實際上一條鏈\((u,v)\)上,可以找到其最值,將鏈分成兩個部分,相當於搞了個堆。只需要記鏈的兩端,就沒有必要將堆處理出來。原來的集合拆成三條鏈即可。

用樹剖實現可以做到空間\(O(n)\)時間\(O(n\lg n)\)


【UR #5】怎樣提高智商

猜:全部都是A 0 0 0 0,答案為\(4*3^{n-1}\),感覺玩不出更大的,於是一交過了?


【UR #5】怎樣更有力氣

要每次對於一個鏈上的點集,以及一些邊,用補圖的邊合並連通塊。

首先把有邊連接的點統計一下。如果存在沒有邊連着的點,那么在補圖中它連着所有點,此時可以合並整個點集。

否則,顯然\(m\ge \frac{n}{2}\),於是暴力將點集拉出來做不虧。用常規的補圖生成森林的方法可以做到\(O(m)\)(比如選出一個度數最小的,它和沒有邊相連的直接合並,和它有邊的點對於所有點暴力連邊,因為最小度數不超過\(\frac{2m}{n}\),所以時間是\(O(\frac{2m}{n}n)\)的)。

第一種情況合並整個點集不能暴力。我的寫法是另外維護個並查集,表示樹上顏色相同的連通塊。

時間\(O((n+m)\alpha)\)(如果不算求LCA的話)


【UR #5】怎樣跑得更快

考慮方程組\(\sum_{j=1}^n f(\gcd(i,j))g(i)h(j)x_j=b_i\)

\(f(n)=\sum_{d|n} fr(d)\)。求出\(fr(d)\)。原式化為:\(\sum_{d|i} fr(d)\sum_j [d|j]h(j)x_j=b_i/g(i)\)。其中\(\sum_j [d|j]h(j)x_j\)記為\(s(d)\)

\(\sum_{d|i} fr(d)s(d)=b_i/g(i)\),可以解出\(fr(d)s(d)\),除以\(fr(d)\)得到\(s(d)\)(模意義下,如果\(fr(d)=0\),如果\(fr(d)s(d)\neq 0\)無解,否則\(s(d)\)可以任意欽定)。

根據\(s(d)\)的定義式又可以解出\(h(j)x_j\),進而得到\(x_j\)

全程用普通的狄利克雷除法操作即可。


【UR #6】智商鎖

竟然是亂搞題……

隨機1000個點數為12的圖,記下其生成樹個數\(f_i\)。然后找到\(f_Af_Bf_Cf_D\equiv k\pmod p\)。可以通過折半實現。

適當調參可以過……


【UR #7】水題生成器

猜了個做法過了。題解說那是“逆n階乘表示”。

大概是,設\(a_i=n(n-1)(n-2)\dots i\),那么域內每個數都可以表示成\(\sum a_ib_i\)的樣子,其中\(b_i<a_i-1\)

於是貪心地確定即可。


7120. 【2021.6.12 NOI模擬】多項式因式分解

如果先乘\(x\)的若干次方將最低項次數補為0,那么分解是唯一的。

首先求出這個分解。每次以0次項下一項的次數搞一搞即可。分解時間\(O(60n\lg n)\)

后面就是要做個背包,以湊出負數最低次數。

直接做背包,只存有值的位置。發現有值的位置其實不超過\(n\)。於是時間\(O(60n\lg n)\)


【2021.6.12 NOI模擬】樹猜

常規的交互題。隨機增量構造。當前維護一棵虛樹以及它的鏈剖分(每個非葉子節點都有重兒子,重兒子欽定為子樹中節點出現時間最小的兒子)。

加入某點\(u\)\(rt\)的子樹中:

  1. 找到\(rt\)所在重鏈的最低點\(d\),令\(t=query(u,d)\),分類討論:\(t=d\)\(u\)設為\(d\)重兒子結束),\(t\)沒有出現過(二分找到\(t\)的位置,插入並將\(u\)作為其輕兒子),\(t\)出現過。
  2. 如果\(t\)出現過,令\(c=query(u,lightson(t))\),分類討論:\(c=t\)\(u\)設為\(t\)輕兒子結束),\(c\)出現過(遞歸進入\(c\)子樹中插入),\(c\)沒有出現過:此時\(c\)一定是某個\(v\in lightson(t)\)\(u\)的祖先,二分出這個\(v\),搞一下結束。

分析下次數:每次二分之后必定伴隨着一個點加入;每次經過一條輕邊需要\(1\)次,期望\(O(\log)\)。(最壞情況是一條鏈,鏈上每個點掛着一個葉子。於是如果一個葉子能產生影響,它應該是父親所在子樹中除父親外出現得最早的。於是貢獻大概是\(\sum_{i=2}^n\frac{1}{i}\)這樣的形式。)

於是總體\(O(n\lg n)\)


ARC122

A,B略

C:首先可以斐波拉契數列快速逼近\(n\)。然后可以看做:對於當前數列,從前往后,可以選擇將當前位置加一,然后更新后面的數列。本質上相當於斐波拉契進制。

D:決定權在后手,后手心中所想的任意一個配對方案,他都可以做到。如果最高位為1的有偶數個,就分成兩部分分開做;如果有奇數個,一定存在一對異或后最高位為\(1\)。於是最高位為0和1中的數分別找一個,使得其異或最小。用Trie搞搞即可。

E:顯然當前集合的子集的答案比當前集合不會更難。每次找到一個能丟到最后面的數,如果能找到,剩下就是個子問題,不會更難;如果不能找到,一定無解。判定的時候算\(gcd(v,lcm(\dots))=lcm(gcd(v,\dots))\)


7125. 【2021.6.16 NOI模擬】裝備

將題目給出的二元組看成有向邊。於是基環內向樹不能動,現在只考慮內向樹。從高到低考慮,嘗試貪心搞,如果換更優,就嘗試將祖先都向上頂一格;如果不換更優,就將子樹全部標記不能換。


7126. 【2021.6.16 NOI模擬】比賽

首先可以寫個普通的DP:\(f_{i,l,r}\)表示\(i\)\([l,r]\)中勝出的概率。時間\(O(n^5)\)可以過n=150

發現\(f_{i,l,r}=f_{i,l,i}f_{i,i,r}\)。於是將其變成兩個狀態\(f_{l,r},g_{l,r}\)分別表示\(l\)\(r\)獲勝的概率。然后是\(O(n^4)\)

將轉移方程寫出來,發現大概是三個區間拼在一起。可以搞個輔助DP先拼兩個。於是時間\(O(n^3)\)


7124. 【2021.6.15NOI模擬】苯為

發現對於某條點數為\(l\)的路徑,貢獻為\(g_{l(A+1)}(k-1)^{(n-l)(A+1)}\),其中\(g_i\)表示長度為\(i\)的環染色的方案數。顯然\(g\)可以寫成矩陣乘法的形式。於是大概是要對\(T^l\)求和,其中\(T\)是某矩陣。隨便搞即可。


7122. 【2021.6.15NOI模擬】西克

\(O(n\lg n)\)過不了2e6……

點分治,向上的可以O(1)搞,向下的因為我菜不會所以我遞歸到下一層繼續做。於是時間\(O((n+q)\lg n)\)

題解大概是拆成\(x\to lca(x,y)\)\(lca(x,y)\to y\)。向上:先計算\(f_x\)表示最近的祖先滿足\(b_x=a_{fa_x}\),連成森林,遍歷森林,在棧上二分得到;向下:用個可撤銷並查集,遇到某個點將\(a_x\)\(b_x\)合並在一起。有可能新開一個\(b_x\),然而同色的\(b_x\)在之前已經被合並,另外開一個,並且將其它獨立的\(b_x\)和它合並。時間\(O(n+q\lg n)\)


2021 計蒜之道 精英組 決賽 Day1

A:略

C:把數字按順序排成個環。對於每個位置,求出以它開頭,能到達的最后是哪個。求出來之后倍增跳一下。需要維護一段區間的點在樹上的直徑。


2021 計蒜之道 精英組 決賽 Day2

A:算不合法的。不合法即某個大於總重一半,發現不會同時出現兩個不合法所以不用進一步容斥。折半搜索算一算即可。

C:發現可以視作\(x\to x+popcount(x)\)。於是大概是要:找兩者的LCA,然后往后跳幾步。可以發現每次增量最多\(18*9\),不會很多,於是除了最后三位之外,前面一定是可以每次加不超過\(1\)的。記個\(f_{p,s,j}\)表示前面若干位和是\(p\),后面三位是\(s\),其中第\(4\)位到\(j-1\)位都是\(0\),要讓第\(j\)位加一,的最少步數以及后面三位會變到哪里。然后詹增即可。注意跳的過程類似於樹狀數組,要從低位向高位掃一下,然后再掃回來。


LOJ 6764. 「THUPC 2021」鬼街

質因數最多有\(6\)個。假設閾值為\(k\)。當警報響起的時候,至少一個質因數處大於等於\(\frac{k}{6}\)

所以質因數設置這個小閾值。如果超過小閾值就看看是否已經超過閾值。次數為\(\log_{\frac{6}{5}}k\)

時間\(O(m\log_{\frac{6}{5}} V \lg m*6)\),非常卡。windows上57s,虛擬機上8s,LOJ上7s……


7128. 【2021.6.18 NOI模擬】雙⾊球

生成函數顯然是\(\frac{(1+x)^n}{1-x^{m-1}-x^m}[x^n]\)。雖然這看着很簡單但其實不可做……

展開得\(\sum_i \binom{n+i}{mi}\)。令\(F(n,k)=\sum_i \binom{n+i}{mi}\),發現\(F(n,k)=F(n-1,k+1)+F(n-1,k)\),並且\(F(n,m)=F(n+1,0)\)。於是將其拍成一維,令\(f(nm+k)=F(n,k)\),於是\(f(n)=f(n-m)+f(n-m+1)\)。常系數齊次線性遞推即可。

簡單的做法:如果最終選擇什么已經確定,那么就是個簡單的遞推,可以用矩陣\(A^k\)表示。然后考慮哪些被選,選就乘\(A\)否則乘\(1\)。於是要求\((A+1)^n\)。還是用常系數齊次線性遞推搞搞。


7129. 【2021.6.18 NOI模擬】數學分析

一次\(x\)變成\(\phi(x)\)相當於對它的每個質因子取一個將其減一。每次減一一定會出現2的因子。於是每步都一定會有個\(2\)變成\(1\)(除了奇數的第一步)。於是只要求每個質數做這樣的過程能產生多少個2即可。

然后生成函數卷一下。


7130. 【2021.6.18 NOI模擬】計算⼏何

根據pick定理,題目等價於求面積為\(1\)的三角形數。

用最小的矩形框柱三角形。分三種情況:三角形一個頂點在矩形頂點,兩個頂點在矩形相鄰頂點,兩個頂點在矩形對角頂點。

根據范圍分析得第一種情況面積大於1,第二種情況很好算。剩下第三種。

引理:當\(m\perp n\)時,方程\(ma-nb=1\),在\(a\in[0,n-1],b\in[1,m]\)內的解有且唯一。

配合這個引理進行一波證明。可得:長寬gcd為1時(除了長寬等於1),有一解;gcd為2時,有兩解。

(證明的時候巧妙運用對稱性可大大簡化)

列出式子之后反演,然后杜教篩即可。


7131. 【2021.6.19 NOI模擬】binom

\(ln\)前綴和。打表打太少跑不過去,要打多點超過代碼長度限制,就用字符串壓了壓……

發現'??-'等於'~',要小心。

實際上積分就好了。


7132. 【2021.6.19 NOI模擬】reward

直接凸優化DP就好了。


7133. 【2021.6.19 NOI模擬】tree

什么做法都有。\(O(n\lg^2 n)\)的就有一堆。

有個\(O(n\lg n)\)的沒卵用的做法:先建虛樹,然后邊分治。

dyp提供了一個比較厲害的思路(應該是\(O(\lg^2n)\)的):假設要合並並計算兩個數組的貢獻(假設下標范圍為\([1,L]\)\(i+j\le lim\)有貢獻)。如果\(L+L\le lim\)就都有貢獻,如果\(1+1>lim\)就沒有貢獻。否則分別拆成左右半邊,兩兩配對遞歸下去做。不知道怎么卡


【UR #8】決戰圓錐曲線

顯然如果\(x_1\le x_2,y_1\le y_2\),則\((x_1,y_1)\)沒用。如果某個點\((i,y_i)\)有用,那么\(y_i\)是后綴最大值。期望有\(O(\lg n)\)個。

線段樹,區間維護最大值。詢問的時候從右往左遍歷線段樹,如果右端點和區間最大值組成的答案能更新答案就遞歸下去。正確性:如果出現這個東西能更新答案,那么必然存在一個\(y_i\)的后綴最大值,它一定是候選點。

時間小常數\(O(n\lg^2 n)\)


7134. 【2021.6.21NOI模擬】旅行計划

建dfs樹,把非樹邊的端點和出發點作為關鍵點拉出來建虛樹,處理出出發點到虛樹上每個點的最短時間。

然后找到虛樹上每個點的管轄范圍,具體一點就是每條邊上能找到個分界點。然后統計一下即可。


7135. 【2021.6.21NOI模擬】搬磚

稍微分析可得答案求\(\gcd(h_i-h_1)\)。用數據結構隨便維護即可。


7136. 【2021.6.21NOI模擬】尋覓

ls的做法:從后往前,如果當前位置未標記,將其染成顏色1並將其相鄰(只保留前面的位置)的位置標記;如果標記就遞歸到下一層做。歸納易證這是對的。

題解神仙做法:首先可以用3個顏色搞出長度4。每3個分成一組,每組取出出現時間最早的做子問題。回來的時候,對於沒有被染色的點,最壞情況下要做長度4的問題,搞一搞即可,顏色增加3。


7137. 【2021.6.22 NOI模擬】⼈贏的情書

首先由\(s_{p_i}\le s_{p_{i+1}}\)。然后確定一下是否不能取等:比較\(rk_{p_i+1}\)\(rk_{p_{i+1}+1}\)即可。

然后是個保序回歸。\(<\)可以通過將后面的信息(\(s\)\(v\))-1變成$\le \(。回去看論文有個\)L_p\(均值的概念,在\)p=1$時是取區間中位數。所以如果用單調棧的做法,要用個數據結構(比如可合並線段樹)維護中位數。

也可以寫出個DP。這個DP顯然是個凸函數,每次加個"V"形。可以用線段樹區間修改+區間賦值維護差分數組,也可以:從最低點作為分界,向左和向右維護斜率增加的位置(即維護斜率的差分的差分)。在加"V"的時候,對於最低點所在的那邊(假設是右邊),在最低點處+2,最左邊-1相當於將第一個斜率增加的點移到另一邊。用對頂堆維護。這題中可以只用一個堆。


7139. 【2021.6.22 NOI模擬】重建計划

前半:關鍵點之間求最短路然后連成個新圖,在這個新圖上最小生成樹。可以水到46分。

后半:維護個已經選的點集,每次隨機一個不在點集內的關鍵點,拉出一條點集到關鍵點之間的最短路。初始點集選擇一個關鍵點。維護最短路時從點集開始跑,點集新加入點的時候重新擴展。可以水到49分。


6249. 【NOI2019模擬2019.7.3】七星連珠

用個集合冪級數作為矩陣元素。算行列式。為了防止被消掉所以每個位置乘一個隨機系數。

為了更快,跑k進制異或FWT將其化成點值。


【UR #9】App 管理器

依次考慮雙向邊\((u,v)\),如果存在\(v\)\(u\)的路徑並且不經過邊\((u,v)\),那么將其定向為\(u\to v\);否則相反。

因為有解,從\(v\)\(u\)和從\(u\)\(v\)必然有個滿足。如果都滿足,因為有解至少有個滿足,此時可證另一個也滿足。


【UR #10】漢諾塔

按值域分治,將左半段和右半段分開,遞歸做。


【UR #10】世界線

先考慮假設能做無限次query。問題是如何分組使得能夠區分每個點。

有個想法就是排成個大小為\(\frac{k(k+1)}{2}\)的三角形(\(i=1..k,j=1..i,(i,j)\)有點),發現此時每行每列都有特征:行或列上的點的個數不相同。

如果有剩下的呢?欽定\((0,0),(1,0),\dots\)放點。可以發現:此時\((0,0)\)所在行是唯一的包含一個元素的行(特判\(n=\frac{k(k+1)}{2}+1\),此時把剩下的點孤立即可。根據其所在行列的點數為\(1\)即可區分)。可以查出\((0,0)\),然后將和它同一列的都查出來,並去掉它們在對應行中的影響。然后就跟沒有剩下的一樣了。

估計一下query的次數。考慮每次選一個點,暴力查其它點看看是否和它在同個塊中,查出來之后刪掉。發現最壞情況的總次數為\(2\sum_{i=0}^{k-1}n-\frac{i(i+1)}{2}\),算一下發現它在范圍內。


【UR #12】密碼鎖

首先可以想到可以分成集合\(A,B,C\)\(B\)作為一個強聯通分量,\(A\)\(B\)連邊,\(B\)\(C\)連邊,統計方案。

可以將\(A,B\)合並,因為是競賽圖所以一定有且僅有一個強聯通分量沒有出邊,這就相當於計算它的貢獻。記這個集合為\(S\)

首先算它貢獻為\((\frac{1}{2})^{|S|(|S|-1)/2}\)。如果存在某條概率為\(p\)的特殊邊從\(S\)連出去,就乘\(2p\)的貢獻。

發現可以根據特殊邊連出的弱聯通分量來搞,記個DP狀態表示有多少個點在\(|S|\)中,此時的貢獻;然后將各個弱連通分量的貢獻卷起來。對於單個弱連通分量,直接枚舉每個點是否在\(S\)中,計算貢獻即可。


7141. 【2021.6.24 NOI模擬】麻將

最長\(L=24\)。把長度為\(L\)的所有子串存到桶里,如果桶沒有滿就嘗試將其\(L\)往下壓,此時每個狀態去掉開頭或結尾得到下一個狀態。時間\(O(n)\)然而究極卡


7142. 【2021.6.24 NOI模擬】德州撲克

進行一堆差分之后,轉化成:線段\(AB\)(左下-右上走向)和\(P\)點為左下的無限長的矩形的問題。

\(AB\)被完全包含:二維偏序。

\(AB\)\(P\)點上方延伸的射線相交(右方的可以對稱計算):掃描線,splay按照截距來維護線段。


7143. 【2021.6.24 NOI模擬】將棋

\(t>T\)的時候,可以\(O(n)\)計算。

\(t<T\)的時候,建出虛樹並對其鏈剖分。鏈內的可以預處理出根到節點的貢獻(最后需要減去每條鏈和總共的LCA到根路徑之間的貢獻),枚舉兩條鏈計算它們之間的貢獻(如果是祖先后代關系要把LCA往上的一段去掉)。於是要算\(\sum t^2\)次,約等於\(nT\)

現在問題是怎么計算這個貢獻。兩段鏈之間的貢獻可以拆成兩段從根開始的路徑之間的貢獻。

可以樹上莫隊。平衡可得\(O(n^\frac{5}{3})\)

也可以進一步對顏色的出現次數分塊。如果大於\(B\),可以暴力,用桶預處理;如果小於\(B\),暴力搞出所有對。后者離線下來。把詢問掛在其中一個節點上,然后遍歷樹。走一條邊的時候,枚舉所有對,給對應的那邊加一。查的時候就可以查另一邊鏈的前綴和。平衡可得\(O(n\sqrt {n\lg n})\)


【UR #13】Yist

按照權值從小到大考慮。如果不刪,選擇的區間不能跨過它,分成子問題。如果刪,先將它刪掉不會更劣。

答案為:對於每個要刪的點,向左向右找到第一個小於它並且不刪的,這中間大於等於這個點的數的個數。取最小值。

因為取最小值,可以從大往小考慮,每次暴力往兩邊擴展,並將擴展過的點打上標記。以后如果擴展到了打過標記的點,因為一定不會更優,所以可以退掉。

時間\(O(n)\)


LOJ3523. 「IOI2021」分糖果

因為直接對整個序列修改很陰間,所以不妨考慮每個位置。

可以將加法移到取minmax后面。於是需要求某個數取一波min和max之后得到什么。

因為后面的minmax有“決定性”。不妨考慮一個后綴,然后維護個\([L,R]\),表示前面小於\(L\)的能變成\(L\),大於\(R\)的能變成\(R\)。從后往前掃,如果某一刻出現了\(L>R\)就得到了答案。

用個以時間為下標的線段樹維護。因為要處理每個數,可以離線,掃過去,支持加入操作和刪除操作。

時間\(O(n\lg n)\)


LOJ3524. 「IOI2021」鑰匙(口胡)

\(S_i\)表示\(i\)能到達的集合。如果\(u\)能到達\(v\),一定有\(S_v\subseteq S_u\)

因為要求最小。假設有\(x\)能到\(y\),現在想知道\(y\)是否能到\(x\),就讓\(y\)走下一個到\(z\),想知道\(z\)是否能到\(y\)……如此往復,發現如果有個點之前走過,就將之前到現在這些點所在一起,繼續做。

解釋:有貢獻一定是一些點集\(T\),滿足它們的\(S\)都等於\(T\)。並且因為是求最小,按照上面一直走下去,如果走不下去說明當前一定是最小;如果走得下去就走。

隨便維護一下。


7151. 【2021.6.28 NOI模擬】tennis

推一波式子,最終可以轉化成求組合數一行的前綴和。

莫隊搞,另外卡億點常。


7152. 【2021.6.28 NOI模擬】bet

寫出個平均數和平均數的平方的線性遞推式,矩陣乘法即可。


7153. 【2021.6.28 NOI模擬】function

構造\(f=g*h\),使得:\(h\)有值的位置少,\(g\)前綴和好求。取\(g(i)=i^m\)發現\(h(i)\)只有powerful number處有值。

枚舉后直接算。


7148. 【2021.6.29 NOI模擬】多項式時間哈密頓回路

二分+貪心。dfs,從祖先帶下來個棧,在回溯的時候嘗試用棧中的東西補。

存下dfs的進棧出棧序以及需要的信息可以做到尋址連續。


7149. 【2021.6.29 NOI模擬】AI高考數學134分

分治,假設\(a_{i..mid}\)是最大值,固定\(i\),看\(j\)\([mid+1,r]\)根據\(b\)\(c\)最大值所屬分成三段,用前綴和搞搞。


7150. 【2021.6.29 NOI模擬】自動化leetcode

分塊。處理出東西使得可以快速查出某個數通過這個塊之后會變成什么。

模擬過程。假設當前定義域是\([l,r]\),如果\(a_i\)在其左右則很好搞,如果\(a_i\)跨過中間,就將比較短的那邊長度翻過來,總長恰好減了那么多長度。於是時間是\(O(V)\)的。

這個過程中用並查集搞搞。實際上在做的過程中並沒有用到查並查集中祖先的操作,所以可以做完之后再路徑壓縮。

適當分配塊大小,時間\(O(n\sqrt V)\)


Codeforces Round #728 (Div. 1)

A:按照dis排序,連一條主鏈使得可以得到這些dis,然后連dis大的往dis小的連負兩者差的邊。

B:考慮\((u,v)\)的貢獻。枚舉\(rt\),設\(u,v\)路徑上距離\(rt\)最近的點為\(x\),則貢獻只和\(dis(u,x)\)\(dis(v,x)\)有關。設\(f_{i,j}\)表示這個貢獻。相當於一個鏈上,左邊\(i\)個點右邊\(j\)個點,每次等概率左右擴展,問先擴展到最右邊的概率。容易dp得出。


AGC054

A:假如兩端不同一次就行;否則看看是否找到\(i\)滿足\(s_1\neq s_i,s_{i+1}\neq s_n\),如果能找到就兩步,如果找不到可證無解。

B:考慮兩個人最終得到的數的各自的排列。發現想到得到這個結果,有且僅有一個總共的排列對應。容易直接構造得到。

C:設\(f_v\)表示\(v\)前面大於\(v\)的值的個數(\(v\)是值不是下標)。正着做的話,每次一定可以讓某個\(f_v>K\)\(f_v\)減一,最終結束狀態一定是所有\(f_v\)\(K\)取min。反過來,考慮有哪些狀態做的結果是這個狀態,顯然就是對於所有\(f_v=K\)的位置,\(f_v\)原來可以取到\(\ge K\)。並且可證只要\(f_v\le n-v\)就一定存在方案且對應方案唯一。

E:令\(p_n>p_1\)。充要條件:\(\exist i\in [1,n-1]\)\(p_i\le p_1,p_n\le p_{i+1}\)

充分性:找到這個\(i\)。把值域根據\(p_1\)\(p_n\)分開,先從大到小依次插入\((1,i)\)中小於\(p_1\)的,再從小到大依次插入\((i+1,n)\)中大於\(p_n\)的,然后從小到大依次插入\((1,i)\)中大於\(p_1\)的,再從大到小依次插入\((i+1,n)\)中小於\(p_n\)的。

必要性:歸納。反證,在對於任意\(i\)都不滿足的情況下,將序列分成兩段,需要兩段都可行。根據可行的必要條件推回來,發現和假設矛盾。

然后計數。直接容斥推不出。考慮求出不合法的。設以\(p_1,p_n\)為分界的三個部分有\(x,y,z\)個,則貢獻為\((\prod_{i=y}^{x+y-1}i)(\prod_{i=y}^{z+y-1} i)\)(因為x的只能跟在x的或y的前面,z的只能跟在z的或y的后面,故能分開計算)。

推推式子,適當使用生成函數,就能做到\(O(1)\)計算。


6056. 【GDOI2019模擬2019.3.13】鹼基配對

按照套路用FFT減法卷積搞一搞即可。


6058. 【GDOI2019模擬2019.3.13】false-false-true

如果分別計算每個點對終點的貢獻,就是\(\frac{\min(i,j)}{i+j}\frac{\binom{n}{i}\binom{m}{j}}{\binom{n+m}{i+j}}\)。可以想到卷積但是有\(\min\)不好搞,於是要寫分治FFT。用力卡常可以過。

ls的代數推法:對於遞推式\(f_{i,j}=\frac{\min(i,j)}{i+j}+\frac{i}{i+j}f_{i-1,j}+\frac{j}{i+j}f_{i,j-1}\)。令\(g_{i,j}=f_{i,j}-\min(i,j)\),可以發現\(g_{i,j}=\frac{i}{i+j}g_{i-1,j}+\frac{j}{i+j}g_{i,j-1}-\frac{1}{2}[i=j]\)。然后計算每個\(i=j\)產生的貢獻即可。

lzc的幾何推法:令\(n\le m\)。畫出個從\((0,0)\)\((n,m)\)的折線圖,再畫個從\((0,0)\)\((n,n)\)的直線。走的時候,每次如果往靠近直線的方向走就會有貢獻(如果是算對的期望)。根據直線將折線划分,發現每段向下和向左的個數相等。於是總共走了\(n\)步有貢獻。然而實際上如果恰好在直線上,方向不確定,會有\(\frac{1}{2}\)的貢獻。於是另外計算直線上的點的貢獻即可。


6057. 【GDOI2019模擬2019.3.13】小凱的疑惑

分塊三層。最下面那層可以枚舉所有情況,預處理,然后O(1)查。到第二層,一共有層長種可能,枚舉之,並依靠下面那層的信息計算;到最上面那層,固定位移模第二層層長,枚舉之,根據第二層信息計算。

調參和時間復雜度估計咕咕咕。


LOJ3525. 「IOI2021」噴泉公園

考慮沒有四個點在同個格子的部分分。此時不會有相差恰好一個格子的豎線和橫線。可以對格子黑白染色。黑色的格子負責染上邊或下邊,白色的格子負責染左邊或右邊。

魔改一下:還是黑白染色。先將所有可能連的邊連上,然后依次從上到下,從左到右考慮每個方格。如果某個方格四個點都有,那就刪掉左邊(白格)或刪掉右邊(黑格)。

考慮這個刪邊的過程。在刪邊前,一直是聯通的。要操作某個四方格的時候,由於欽定了順序,它的邊沒有被動過,四條邊連着;此時刪掉其中一條,自然還是聯通的。


LOJ3526. 「IOI2021」修改 DNA

IOI竟然有簽到題。

欽定一個置換,答案為點數-輪換數。如果\(a_i=b_j\)則可以連邊\(i\to j\)。不妨根據\((a_i,b_i)\)統計,然后先湊自環,再湊重邊,最后三元環。


LOJ3527. 「IOI2021」地牢游戲

寫題的時候忘記把臨時變量賦值到倍增數組上了,時間復雜度直接假掉然而我調了半天參數。

看到如果\(\ge s_i\)則加\(s_i\),不妨根據\(z\)\(2^k\)分階段。對於階段\(k\),此時\(z\ge 2^k\),令\(s_i<2^k\)的戰勝,\(s_i\ge 2^k\)的戰敗。用個倍增搞一搞,跳到第一次發現\(s_i\ge 2^k\)的戰勝了,此時\(z\)就會大於等於\(2^{k+1}\),到達下一個階段。

總結:如果每次戰勝一個之前沒有戰勝的,就更新倍增數組,這很虧;划分階段,這樣就把更新倍增數組的次數收束到了\(O(\lg V)\)次,並且由於如果忽然戰勝了個\(s_i\ge 2^k\)就可以跳到下個階段,這樣就保證了正確性。

理論上時間\(O(q\lg^2V)\)。為了卡空間寫了個非二進制的倍增(前面幾步可以暴力,能省很多空間)。實際上也可以鏈剖+二分,環上特殊處理。因為不想處理環相關操作所以沒寫哪個。


7157. 【2021.7.3 NOI模擬】猜猜

用個set維護相鄰的。對於每個點記個\(pre_i\)。再用個線段樹維護個\(pre_i\)最大的,找的時候線段樹上往后找\(k\)個。時間\(O(nk\lg n)\)

我的方法比較蠢,維護了區間中\(pre_i\)的前k大,時間復雜度一樣的。


7159. 【2021.7.3 NOI模擬】是誰(口胡)

暴力題……適當壓位,以及將多個操作壓在一起,用某些手段搞搞……

現在才知道角谷猜想沒有被證明,虧我比賽時給它證了好久……


100207. 決心

正確地玩過之后發現如果長度大於\(2\)則只需要操作2次。具體構造方法:任選某個點\(x\),其前驅后繼分別為\(z,y\),連邊\(z\to x\to y\),操作\(z\)\(y\),就可以把\(x,y\)分到一起然后\(z\)連向\(y\)的后繼。然后因為\(z\)被操作了,所以\(z\)要成為新的\(x\),繼續操作,后面就是唯一的了。所以操作一個環的方案數是環長次。

然而可能會有兩個環合並到一起的情況。發現由於合並的時候之前操作的兩個點不能操作了,以它們分界的兩部分必須要對稱。所以只能是兩個大小一樣的環合並在一起。

於是對於同環長,貢獻為\(\sum_{2i\le c}\binom{c}{2i}i!!L^{c-i}\)

枚舉所有本質不相同的情況計算即可。


6132. 【NOI2019模擬2019.4.18】構圖

如果全部是正數或負數,策略就是:按照絕對值從小到大排序,枚舉一個長度為偶數的前綴,這個前綴內部兩兩配對,配對互相包含(即小的配大的)。其它的點都和一號點連邊。

如果兩者都包含,顯然正數要連負數。枚舉負數的一段前綴,用上面的方法做;然后后面的負數和前綴依次連邊,絕對值最大的負數可能連多個正數。

可以做到\(O(n^2)\)。也可以用FFT優化但是沒必要。


6088. 【GDOI2019模擬2019.3.27】白

暴力可以預處理出\(A^i\),后面的部分用多項式操作和FWT解決。

前面這個暴力\(O(n^3m)\)太慢。實際上可以求出\(A\)的特征多項式,於是可以得到\(A^{k}\)關於\(A^i,i\in[k-n,k-1]\)的遞推式。這個遞推式只需要按位相加。

對於每個FWT中的狀態,大概能求出個序列\(F(x)\),由於已經知道是遞推所以可視作\(\frac{P(x)}{Q(x)}\)\(P(x)\)可以通過\(F(x)Q(x)\)取前面\(n\)項得到。然后要求\(\frac{1}{1-(\frac{P(x)}{Q(x)}-C)}\),化簡之后直接多項式求逆即可。

求特征多項式可以暴力插值搞,也可以不求后面直接BM出遞推式。

全程其實都可以不用FFT操作,常數夠小。


7160. 【2021.07.06 NOI模擬】合成小丹

每次合並兩個,把這個過程畫出來可得一棵非葉子節點都有兩個兒子的二叉樹,葉子的貢獻是\(\frac{a_x}{2^{dep_x}}\)。並且\(\sum\frac{1}{2^{dep_x}}=1\)。反過來,如果欽定了\(dep_x\)滿足這個條件,就一定可以構造出\(dep\)分布是這樣的樹。

按位確定。問題變為:有個\(s\),要求選擇某些點,使得\(\frac{a_x}{2^{dep_x}}\subseteq s\)。對於每個\(x\),有個\(dep_x\)可以取到的集合\(D_x\)。現在還需要滿足\(\sum\frac{1}{2^{dep_x}}=1\)。先看看有沒有能選\(dep_x=0\)的,如果沒有再看\(dep_x=1\)的,能選就選。總體概括為:現在將當前點集分成\(c\)組,每組貢獻\(\frac{1}{2^k}\)。如果存在方案,並且剛好存在某個能取到\(dep_x=k\)的,可以將它所在的組變成它自己,其它組員任意丟到其它組,然后\(c\)減一變成子問題;如果找不到,就繼續細分找下一層。於是就證明了貪心的合理性。

一層一層做,直接模擬上面的過程是\(O(nw^2)\)的。可能TLE。

觀察,如果\(\sum \frac{1}{2^{dep_x}}\ge 1\),我們必然能找到個子集使得\(\sum \frac{1}{2^{dep_x}}=1\)。於是所有\(dep_x\)\(\min(D_x)\),判斷是否\(\sum \frac{1}{2^{dep_x}}\ge 1\)即可。(這樣也證明了上面那個貪心的合理性,不過從上面推到這里好像不行)

維護\(\sum \min(D_x)\)。觀察\(s\)\(p\)位從\(1\)變成\(0\)\(D_x\)的變化,有D[x]=D[x]&~(a[x]>>p)。於是就可以做到\(O(nw)\)了。


7161. 【2021.07.06 NOI模擬】路過中丹

判定條件:包含一個長度為\(3\)的奇回文串,或能被若干個偶回文串覆蓋。

考慮從中點開始往走,要求每步相同。如果有奇回文串,就可以先一起走完所有點到中間,分別到兩邊停下來;如果沒有奇回文串,從中點往兩邊走,發現不能恰好一個轉向(否則有奇回文串),於是只能走偶回文串。

求出包含\(i\)的回文串中左右端點最小的偶回文串\([L_i,i],[i,R_i]\)。如果不合法,那么存在\(i\in[l,r],L_i<l,R_i>r\)。用數據結構搞搞即可。可以做到\(O(n\lg n)\)

題解做法是分治。對於\([l,mid]\)中的點,設\(Right(i)\)表示若干個偶回文串覆蓋\([l,mid]\),最左到\(l\),最右最小是多少。另一邊也記個\(Left(i)\)。詢問的時候就看\([Right(l)\le r\and Left(r)\ge l]\)。處理\(Right\)時,從右往左做,搞出個轉移方程(枚舉\(i\)為左端點的串),然后借助回文自動機維護。直接做要回文自動機上倍增。發現轉移時,如果下一個轉移的長度超過上一個轉移的一半,那么上一個轉移完全可以用兩個下一個轉移替代。於是只需要保留\(O(\lg )\)種轉移。維護個轉移位置的指針,分治過程中從上層到下層指針移動單調。總時間復雜度是\(O(n\lg n)\)


7162. 【2021.07.06 NOI模擬】膜拜大丹

畫出坐標\((i,a_i),(b_j,j)\)。如果兩者是左上-右下分布就是個二元環。考慮一個環,它一定存在個左上-右下分布的邊,那不如替換成邊形成的二元環。

后面直接貪心就行了。掃描線,用set維護,找最緊的。

題解轉成了找最大獨立集,於是變成了格路問題,走個從左下到右上的,每次向右向上,貢獻為格路上方的\(B\)和下方的\(A\)。寫出DP之后進行了一波分析、優化、數據結構得到正解。


LOJ3175. 「IOI2019」排列鞋子

假如欽定一個排列表示最后到哪里,那么排序的逆序對個數就是答案。

對於存在一種方案,考慮其排序后相鄰的兩對鞋原來的相對位置,看看對其調整能不能更優。於是可以得到:如果某對鞋二維偏序小於另一對鞋(兩維分別為其所在位置的最小值和最大值),那么就一定排在前面。

欽定一個順序使得二維偏序小的一定在大的前面,然后就過了?


7164. 【2021.07.08 NOI模擬】七管熒光燈

看做“杏仁”。發現連接端點的路徑不能存在兩條同時完全操作。

結論:如果各路徑上權值相同,三條路徑權值異或和為0,先手必敗。

證明:顯然必敗態不能變成必敗態;如果不是必敗態,設各個路徑最小值為\(x,y,z\),然后\(x,y,z\)中取一個像nim游戲那樣調整一個值使得異或為0。將其它值都調成其所在路徑上的最小值。於是就一步到達必敗態。

后面就是ljDP。


7165. 【2021.07.08 NOI模擬】混亂(口胡)

wmy的做法:

平衡規划。\(k\le T\)時,找出包含\([S_i,S_j]\)的區間中權值最小的區間;\(k>T\)時,直接\(O(n\lg n)\)搞過去,這部分時間\(O(\frac{n^2\lg n}{T})\)。前面部分:分塊,每個點存包含它到后面每個塊尾的權值最小區間,線段樹維護之。一次修改\(O(\frac{n}{B}\lg n)\)。詢問時:先處理右端點超過詢問右端點所在塊的區間的貢獻,對於散塊,因為隨機所以可以看成\(O(B)\)個有影響的區間,離線一下詢問(一個操作中的查詢\([S_i,S_j]\)),跟這些有影響的區間歸並一下,時間似乎是\(O(B\lg n)\)

感覺時間是\(O(n\sqrt n \lg n)\)的。


【2021.07.08 NOI模擬】超立方體

老原題了。

核心發現是:可以通過查\(d(x,rt)\bigoplus d(y,rt)\bigoplus d(x,y)\)得到\(LCA(x,y)\)

按照老套路增量+維護虛樹重鏈剖分即可。

我寫了隨機鏈剖。不過實測一條鏈的有一點概率會掛,加了個表現優異的優化:

在重鏈上二分那一部分,考慮求出插入點和其它每個點的LCA的異或和,顯然這個東西應該是祖先的點異或和 異或 插入點 后代的點的個數次。這個東西由插入點的最近祖先唯一確定。要找最近祖先,相應地求出的這個東西,要求跟上面問的相等,這是個必要條件。

在滿足這個必要條件的集合里二分。如果要卡,那么需要中間一坨點異或和為0或者為插入點這樣的數據,應該不好造,況且我本來就是隨機增量,就更難卡了。於是這部分就變成幾乎\(O(1)\)啦。優化后鏈的大概跑20000。


7167. 【2021.07.12 NOI模擬】簡單的希爾伯特曲線題

結論:行的和相等。

證明考慮從頭尾同時走,任意時刻兩點位置關於中軸對稱。

知道之后分類討論,遞歸即可。


7169. 【2021.07.12 NOI模擬】簡單的bzoj題

老原題了。

寫出個DP,線段樹維護區間答案。這個DP是凸的所以可以閔科夫斯基和。

對於詢問,先套個wqs二分,找到線段樹對應若干個區間,在上面二分得到當前最優值。時間\(O(n\lg^2 n\lg V)\)能過。

如果wqs二分用個整體二分,線段樹各個區間中最優值的候選位置在整體二分中每層狀態的總長為區間長,可以省去后面那個二分,時間\(O(n\lg n\lg V)\)


7168. 【2021.07.12 NOI模擬】簡單的字符串題

比賽時為什么沒有想過求兩個位置的LCP啊……

第一問:把貢獻關於位置差和LCP的關系式寫出來,化一下。可以在后綴樹上強行做,線段樹+dsu on tree,時間\(O(n\lg n)\);也可以枚舉位置差\(d\),在\(kd\)的位置放個觀察點,相鄰位置查LCP和LCS,搞一搞,時間\(O(n\lg n)\)

第二問:如果建SAM自然最方便;我因為寫了SA不想寫SAM,就這樣:考慮SA其實相當於后綴樹上dfn,height相當於兩兩LCA。維護一條祖先后代鏈上每個點的貢獻。按順序遍歷SA,每次先將height后面的貢獻清空,然后問鏈和,再對鏈區間加。時間\(O(n\lg n)\)

PS:不會卡常於是將ST表的前后兩維交換就過去了?(交換后前一維表示跳的步數,后一維表示起點)


7170. 【2021.07.13 NOI模擬】伽銨目

\(f_i\)表示sg為\(i\)的樹的大小最小是多少。顯然\(f_i=1+\sum_{j=0}^{i-1}f_j\),得到\(f_i=2^i\)。於是sg的級別是\(O(\lg n)\)的。

搞個暴力:\(g_{i,j}\)表示\(i\)為根,sg值位\(j\)的方案數。轉移的時候用個狀壓DP,用FWT優化。

另外有個結論:sg為\(k\)的點數是\(O(\frac{n}{2^k})\)級別的。大概說明一下:首先假設子樹不相交,那么每個都有\(2^k\)的點數;考慮兩個這樣的點為祖先后代關系,中間沒有其它這樣的點,那么最多算多了\(2^{k-1}\)的貢獻,剪掉。於是攤下來每個點至少有\(2^{k-1}\)的貢獻。

時間\(O(n\lg^2 n)\)


7171. 【2021.07.13 NOI模擬】笛鐳特

直接用ETT模擬即可。

其實可以不用splay。處理某點之后,先處理子樹內的,然后將整個子樹區間賦值(刪除),再搞祖先的。


7172. 【2021.07.13 NOI模擬】鎂克鍶

卡空間卡時間然后放個bitset+分塊過。

題解:分塊,用bitset維護塊的區間的顏色。

我的考場做法(70分):定期重構,維護主席樹,線段樹上二分的時候暴力往下找,如果找到時間塊內動過的就不理它;時間塊內動過的另外用個set處理。空間\(O(n\lg n)\),時間\(O(n\sqrt n\lg n)\)

正經的\(O(n\lg^2 n)\)時空做法:先在外面套一層維護權值區間信息的數據結構,內層要查這個權值區間中,是否有值不在詢問區間中出現過。對於每個值,根據其出現位置將序列划分成若干區間。我們想問詢問區間是否被其中一個區間包含。可以在划分的區間中,每個右端點上掛個左端點的位置;然后以詢問區間右端點為開頭的后綴中找掛的最小的左端點位置。內層需要用個支持單點修改,區間查詢最小值的線段樹,另外需要在葉子中維護個set以插入刪除。


Codeforces Round #732 (Div. 1)

A:先排序。顏色相同的塊內部交換一下,大概是有個01序列,每次可以把00變成11或反之;可以發現可以轉化成交換距離為2的,然后再搞;於是先分位置奇偶性排序,看看排完之后是否前面全0后面全1。其實也可以一開始就分奇偶性排序,然后看整體是否已經有序。

B:把原串拆成0,010,11,發現這些之間可以任意移動,另外一堆11也可以和一個010組合起來。枚舉多少個11用於組合,記個數。

C:建圖,如果兩個排列有公共點就連邊。如果當前存在一個排列,存在(顏色,位置)的二元組獨屬於這個排列,那么它一定要被選,選上之后刪去和它相連的點,並且消去它和它們的影響。一直這樣搞搞。如果不存在這樣的排列:假設之前消過\(x\)個,由於一定存在和它們配對的,所以至少消掉\(2x\)個排列;現在未確定的(顏色,位置)是\((n-x)n\),而總數不超過\((2n-2x)n\)。根據鴿巢原理,此時所有(顏色,位置)恰好出現了2次。連邊,此時一條邊兩端點選和不選的狀態是相反的,所以可以黑白染色。因為保證有解所以沒有奇環。

D:不太能確定各個等差數列是什么,於是用代數方法搞搞。各時刻的位置和顯然是等差數列,於是可以確定第一個答案,並且知道修改的增量;再搞出此時的平方和應是什么,現在是什么,得到修改后平方和的增量;根據兩者列個方程可解。


7175. 【2021.07.14 NOI模擬】種蘑菇

稍微推一推可得\(S\)的貢獻為:\(\sum_{t|u\in S}\sum_{d|t}d^{|S|}\mu(\frac{t}{d})\)

枚舉\(d,t\),提取所有作為\(t\)倍數的點生成的子圖,算可能的\(S\)的貢獻和。因為已經枚舉了\(d\)所以不需要記\(S\)的大小。

時間是\(O(n\lg^2 n)\)


7173. 【2021.07.14 NOI模擬】按鈕

普通暴力:記個\(F_{l,r}\)表示當前數為\(l\),確定目標在\([l+1,r]\)所花的最大步數;\(G_{l,r}\)記個對稱的。轉移的時候枚舉個\(md\)然后分成兩個子問題。

因為dp值不大(題解說是\(45\))所以換一下狀態和dp值。記\(f_{l,c}\)表示當前數為\(l\),最大步數至多為\(c\)\(r\)最大能是多少;\(g_{r,c}\)類似。

轉移:\(f_{l,c}=\max_{g_{md,c-\Delta}\le x+1}f_{md,c-\Delta}\)\(\Delta\)表示操作這一輪的代價。

優化:最外層枚舉\(c\)。記個\(D_s\)作為轉移的中轉。\(s\)形如一個數被挖掉了幾個空的形式。於是從\(l\)變成\(md\)相當於先變成\(s\)再變成\(md\)。一開始將\(f_{md,c-\Delta}\)(此時枚舉了\(md\)要挖掉哪里)的貢獻掛在點\(g_{md,c-\Delta}-1\)上,然后從左往右掃,掃到某點把掛在上面的貢獻加入其對應的\(D_s\)中,算\(f_{l,c}\)的時候枚舉\(l\)挖掉哪里,然后用對應的\(D_s\)轉移。

時間大概是\(45*2^5*10^5\)


7174. 【2021.07.14 NOI模擬】蛋糕

假如已經固定了\(x\)。把\(x\)沒有穿過的拉出來,變成個二維的問題。

選擇的\((y,z)\)可以看做個點,一個矩形被穿過當且僅當它對應的十字架中包含這個點;於是我們希望知道所有十字架交集是否為空。

算補集的並。拆成四個角,每個角維護個階梯。統計的時候,先搞出左下、右下的分界點和左上、右上的分界點,然后把橫坐標分成三段,每段的上下邊界分別由左上左下、左上右下/左下右上、右上右下決定。維護上下邊界的差,如果區間中存在差大於0則有解。

階梯可以用set暴力維護。因為一個點的存活時間是一段前綴和一段后綴,不妨拆成兩個點看。從左到右掃,如果新增了個時間為一段后綴的點,它覆蓋的點一定不會恢復;如果刪除了個時間為一段前綴的點,它剛好覆蓋的點會暴露。每個點只會暴露一次。如果知道哪些點被暴露,之前先反過來操作一遍,此時這個點加入之后覆蓋的點,就是那時刪除后暴露的點。


AGC026C String Coloring

發現如果決定了左半邊的狀態,整個字符串就確定了。折半統計即可。


AGC026D Histogram Coloring

先決定最下面那行。考慮倒數第二行。如果存在相鄰相同,那么方案確定;否則可以繼承或取反。有了高度的限制,相當於往上搞的過程中刪掉了一些點,分裂成幾個問題。對其DP,考慮兩個最近的存在相鄰相同的位置,它們之間的貢獻:先求出各自的失效位置(即哪個小),以此作為區間搞個類似於下包絡線的結構,超出包絡線的極長橫區間個數(2得到這個東西次方)。


AGC026E Synchronized Subsequence

首先划分出若干個極小的a,b出現次數相等的組。每組中每對ab的先后順序是相同的。

考慮局部答案:

1類:如果a在b前出現,答案一定是ab的循環。如果出現aa那么一定可以通過刪掉后面那些將其變成ab。

2類:如果b在a前出現。可證如果第i對ba出現了,第i+1對ba也出現會更優。

全局答案:

從后往前維護個字典序最大的(顯然不同后綴加上相同前綴大小關系還是由后綴決定)。

如果是1類,並且后面沒有出現過2類,那就放最優解。

如果是2類,局部最優解的候選兩兩不互為前綴,所以肯定取局部最優解;用局部最優解+當前答案和當前答案比較,取最優。

時間\(O(n^2)\)


AGC033E E - Go around a Circle

不妨設\(s_1=R\)。首先考慮第一步,可得不存在連續的BB,否則在之間的點走不出第一步。

考慮環上每個R的連續段。s中這么長的第一段R中,這個連續段每個點都要跳那么多步,到了最后都應該到達端點。如果段長為偶數,那么總是存在點跳不到端點,所以段長一定為奇數。另外也得到了個段長的限制。

在s的第一段之后,s的每一段開始,都是從R的連續段的兩個端點出發。跳那么多步又要跳到端點,根據奇偶性和長度又得到了段長的限制。

於是問題變成了:染色,B段長度為1,R段長度為奇數且有個最大值限制。

對其計數。特判下沒有B段的情況。后面將R段和B段合並到一起,變成將環划分成若干個有長度限制的段(要判\(n\)為奇數)。然后用生成函數隨便推推就可以得到\(O(n)\)的遞推式。


LOJ2769. 「ROI 2017 Day 1」前往大都會

好像和NOI2019那道題差不多?

首先建出最短路圖,根據拓撲序進行DP。對於單個極長的鐵路進行分析,列出轉移方程,可以斜率優化。

於是每個極長的鐵路維護個斜率優化用的隊列即可。


LOJ3472. 「JOI 2021 Final」地牢 3

考慮貪心策略:考慮當前點如果吃飽最多能走的范圍,如果范圍內能找到比它小的,就從這個點花盡量少的代價,使得體力值能夠到達那個第一個比它小的(中間不吃);否則范圍內的都比它大,那就在這個點吃飽。

我想了個LCT做法。設\(p_x\)是第一個比它小的。如果\(p_x\)在范圍內,那么連黑邊\(x\to p_x\),否則連白邊\(x\to x+1\)。詢問的時候提取\(l\)到最后的路徑,找到在\(r\)之前的最后一個黑邊,算出\(l\)到這個黑邊的貢獻,再加上黑邊直接到\(r\)的貢獻。至於如何算路徑的貢獻,我本認為如果跳一次黑邊那么一定體力值清空,列出貢獻的式子之后,以黑邊分段分析,顯然是可以方便維護的。然后離線,枚舉\(U\),變化的時候改變一下邊。

然而如果出現了\(x\to y\to z\)\(b_x<b_z<b_y\)的情況,\(y\to z\)是黑邊,但是由於\(z\)不是\(x\)考慮的更小的點,所以有可能在\(x\)吃飽,跳到\(y\),跳到\(z\)之后還有剩余。這就假了。

《如果是在考場上我就直接上了》

靠譜的做法:從后往前維護個單調棧(后綴的前綴最小值),彈棧的時候(棧頂大於當前點)討論加入點和棧頂和棧頂下一個的關系。本來應該是從棧頂到棧頂下一個,現在考慮用當前點補充體力盡量替代棧頂補充體力然后再到棧頂下一個,討論一下。至於\(U\)的限制,可以維護個以\(U\)為參數的函數,用數據結構對這個函數進行修改。


LOJ2288. 「THUWC 2017」大蔥的神力

前面7個點各有各的確定性做法,后面的用random_shuffle或退火亂搞一下。


LOJ3476. 「ROIR 2021 Day 1」繩子

可以轉化為要將一些\((a_i,b_i)\)拼接,要求\(b_{i}+a_{i+1}=d\)

如果\(d\)定:把\((a_i,b_i)\)看成平面上的點,根據限制可以畫一條\(x+y=d\)的直線,\((a_i,b_i)\to (a_{i+1},b_i)\to (a_{i+1},b_{i+1})\)。看到此時\((a_i,b_i)\)出度入度為\(1\),不妨直接將其看成\(a_i\to d-b_i\)的邊。

連邊之后跑歐拉路徑即可(注意判連通性)。

如果\(d\)不定。我們希望\(a_i\)\(d-b_j\)盡量兩兩配對。那大概是\(a_i\)小的配\(b_j\)大的。如果能形成回路那肯定就是最小配最大,如果只是路徑有路徑端點,就用\(a_i\)最小次小配\(b_i\)最大次大跑一遍。


LOJ3067. 「ROI 2016 Day2」二指禪

暴力直接設\(f_i\)表示匹配到\(i\)。處理前綴轉移時用\(f_i\)轉移到\(j>i\),處理后綴轉移時用\(j<i\)轉移到\(f_i\)。lhf管這叫主動轉移和被動轉移。

平衡規划。字符串長小於\(B\)時用上述暴力;大於\(B\)時,求出其和各個位置的LCP,LCS,用數據結構維護個:區間修改(取min)+單點查詢,區間查詢+單點修改。分析下可以把前者的區間修改換成前綴修改,后者的區間查詢看成后綴查詢,這樣就可以用\(O(\sqrt n)-O(1)\)數據結構啦(用點整塊前綴min和散塊前綴min)。總時間\(O(n\sqrt n)\)

lzc的nb做法:一個串的最大border應該只出現了兩次。還是平衡規划,現在處理大串前綴的轉移(后綴的轉移可另外做)。建出border樹。從前往后掃,現在搞出了當前位置能夠匹配的最長前綴(當前位置作為末尾),知道了對應的節點。考慮一個border的等差數列,對比一下上次它們出現時開頭的位置(即決策點候選),以及現在時開頭的位置,發現基本上重復,除了那個最小的border。所以一段只需要改一下。

這個做法盡管時間復雜度劣一些,但好像也有優點:它只用到了被動轉移,意味着主動轉移不方便的情況下它很好做(比如把題目的匹配串換成個Trie)。


LOJ3290. 「CEOI2014」蛋糕

考慮起點一邊。如果\(i\)\(i+1\)前面被吃,並且\(a_{i+1}<a_i\),那么吃掉\(a_i\)之后一定會立刻吃\(a_{i+1}\)。把這樣的\(a_{i+1}\)刪掉,得到起點兩邊的階梯狀的東西。

用set維護一下即可。處理修改的時候我偷懶用了10log,實際上也可以10+log,甚至log^2。


UNR5

D1T1:

考慮倒過來做:設\(dp_{i,j}\)表示第\(i\)對括號,它和包含它的括號中有\(j\)個選B。每個狀態記個0..3次方和。

時間\(O(n^2)\)

D1T2:

首先處理樹同構,將同構的樹壓在一起。於是變成一棵新樹,節點\(u\)記個\(c_u\)表示有這么多個長成\(u\)子樹這樣的子樹壓在了一起。記個\(f_u(x)\)表示\(u\)子樹中方案數的EGF。設\(g_u(x)\)表示\(c_u\)個這樣的樹組合起來的方案數,於是有\(g_u(x)=\sum_{i=0}^c\frac{(f_u(x)-1)^i}{i!}\)。求\(f_u(x)\)就將兒子的\(g\)卷起來之后乘上\((1+x)\)。於是就能做到\(O(n^2)\)

正解: 搞個特殊的重鏈剖分,只認嚴格重兒子。那么重兒子貢獻一定是直接用\(f\)乘上來的。於是對於一條重鏈,就是重鏈上掛的一堆輕兒子的\(g\) ,以及重鏈長度個\((1+x)\) 卷起來。這里可以用合並果子FFT。然后求\(g\)的時候,可以用分治FFT來求。\(G(x)=\sum_{i=0}^c\frac{x^i}{i!}\) , 求\(H(x)=G(F(x))\)

\[G(x)=G'(x)+\frac{x^c}{c!}\\ G(F(x))=G'(F(x))+\frac{F^c(x)}{c!}\\ =\frac{1}{F'(x)}[G(F(x))]'+\frac{F^c(x)}{c!}\\ H(x)=\frac{H'(x)}{F'(x)}+\frac{F^c(x)}{c!} \]

這個東西可以先求出\(\frac{F^c(x)}{c!},F'(x)\)之后分治NTT。

總時間復雜度\(O(n\lg^2n)\)。 (好像如果不合並果子FFT就有\(O(n\lg^3n)\)

D1T3:

結論:一個dfn序合法,當且僅當:對於所有從點\(x\)到點\(y\)的移動,\(dfn_x<dfn_y\)或者\(x,y\)為祖先后代關系。

必要性:對於某個子樹,比這個子樹大的值進不來;因為執行過程中子樹不能變大,所以還是進不來。

充分性:構造證明,每次找\(dfn\)最小的葉子,然后把目標位置為它的值移過來。移動的起點此時一定是它的祖先,並且移動之后其它點的相對順序不變,仍然滿足結論,歸納。

進一步觀察:只要每次搞某個點的時候,起點都在祖先就行。往前分析,在前面也滿足這個條件的情況下,可以把祖先鏈看成個集合,每次放些東西進去,然后把需要的取走。如此,只有對於每個點而言,起點的\(dfn\)不超過其子樹的最大\(dfn\)才能滿足。即\(a_x\le out_x\)

我們考慮\(dp\)出每個點\(out\)的下界。設\(dp_i\)表示\(in_i\)(不要以為是out然后搞錯了后面的結論)的下界,通過調整法證明,按照\(dp\)值從小到大排序轉移最優。

D2T1:

討論一下中點之后,大體上是要找到相同的兩段字符串。在分界點對齊處分段,每段大概是上面12222下面22221這樣。此時如果將長為2的連邊,長為1的和0連邊,於是就變成了從0開始跑歐拉回路。

以上只是大概,細節不論。

D2T2:

\(w=128\)。可以暴力每次用線段樹找到要修改的位置並改之,乍看下去是\(O(nw^2\lg n)\)。經過PT分析,這實際上是\(O(nw^2+qw\lg n)\)。不妨先考慮只有一種修改的情況,我們容易認為是\(O(nw\lg n)\),實際上可以對於線段樹上的每個區間分析,每次對一個區間進行整體修改,勢能就減少\(1\)。線段樹上\(n\)個區間於是只有\(nw\)的勢能。考慮兩種修改,發現除法可能會使得勢能增加,但可以把這部分勢能攤到\(q\)上,變成\(qw\lg n\)

這個東西本身常數不大,加了個底層暴力就過了(

正解:考慮一個普通的做法,除法遞歸下去暴力修改,and打tag,對於每個位維護出現次數。這樣時間大常數\(O((n+q)w\lg n)\)。每位用\(w\)個數存狀態,每次合並需要\(w\)個數對應相加,這樣太慢,換成直接ll普及的那個轉置之后壓位用位運算模擬加法的東西,每次操作是\(O(\lg V)\)。還要處理將某些位上的數清零,發現用這種形式其實也很方便。於是時間優化到了\(O(nw+q\lg^2n)\)


AGC021D - Reversed LCS

考慮從兩邊從中間做,搞兩個指針,在指針相遇的地方處考慮,發現后面可以倒着走另一個指針之前走過的地方(也就是說結果一定是個回文串)。

於是決定走過哪些地方。先DP個沒有修改的配對的位置,然后在這些位置之間插入一些通過修改產生的配對的位置。設\(f_{i,j,t}\)表示指針分別為\(i,j\),沒有修改的配對的位置之間能插入的空隙長度和為\(t\),此時長度為多少。


LOJ3005. 「JOISC 2015 Day 4」Limited Memory

對於每個位置,假裝所有括號顏色相同地找到與其對應的括號,判斷顏色是否相同(注意不管這個位置是左括號還是右括號都要做)


LOJ3350. 「CEOI2020」星際迷航

不是所有博弈題都是非用SG函數不可的……(不過好像也能做只是時間乘了幾個log?)

從后往前,考慮維護后綴的必勝必敗的方案數(定根)。現在接上一棵樹,選擇其中一個根節點和另一個和后綴相連的點,計算新的必勝必敗方案數。用DP的方式思考(因為便於換根),設\(h_{x,0/1,0/1}\)表示\(x\)子樹中,插入了一棵必勝/必敗的樹,現在從\(x\)出發必勝/必敗的方案數。

換根地求出這個東西之后,可以把每次的貢獻寫成矩陣,然后矩陣乘法即可。


LOJ3337. 「BalticOI 2020」病毒

容易想到在后綴自動機上做。設\(f_{i,s,t}\)表示把第\(i\)個串展開后,后綴自動機上從\(s\)\(t\)的總長,最小是多少。

每次轉移,序列表那么長不太方便,於是就拆成len個點表示其的每個前綴。然后就可以把每個序列看成長度為2的。

轉移可以看成:\(f_{x,s,t}\leftarrow f_{a_x,s,u}+f_{b_x,u,t}\)

用類似於Dijsktra的方法轉移即可。


AGC017D

考慮SG函數。如果已經求出了某棵子樹的SG,現在加一個點作為根連向這棵子樹。對於原樹所有狀態,都恰好對應着原樹上加個根。則原來只有一個點的狀態對應兩點相連,此時SG為1;並且發現每個狀態都可以通過刪掉和根相連那條邊,得到SG為0。因此SG函數加一。

於是某個點的SG就是其兒子的SG加一的異或。


AGC029E - Wandering TKHS

考慮從\(x\)走到\(1\),必經路上有個最大值\(m\)。有性質:擴展的所有點都不會大於\(m\)

\(1\)為根建樹,在剛好看到\(m\)的時候,一定會將\(x\)能直接到達的所有小於\(m\)的位置全部走完,再去走\(m\)。小於\(m\)的位置全部走完之后,\(x\)便無法到達\(m\)子樹中其所屬子樹的其它點。於是\(m\)子樹中\(x\)所屬子樹已經固定了。

\(m_x\)\(fa_x\to 1\)路徑上的最大值。\(Q(x,v)\)表示從\(x\)開始在子樹內擴展所有不超過\(v\)的點數(不包括自己)。假設已經求出\(c_u\),現在要求其兒子\(v\)的答案\(c_v\),考慮其答案變化\(\Delta=c_v-c_u\)

如果\(v>mx_u\),則\(u\)之前一定不會擴展到\(v\)。如果從\(v\)出發,\(v\)子樹內會擴展\(Q(v,mx_v)+1\)的節點,考慮\(v\)子樹外,這部分相當於從\(u\)開始擴展。於是\(\Delta=Q(v,mx_v)+1\)

如果\(v<mx_u\),則\(u\)之前已經擴展到\(v\)\(v\)子樹外的部分仍然相當於從\(u\)開始擴展,不變,\(v\)子樹內的增量是\(Q(v,mx_v)-Q(v,mx_u)=\Delta\)

問題變為如何計算\(Q(v,mx_v)\)\(Q(v,mx_{fa_v})\)

用數據結構有若干種計算方法。實際上直接記憶化搜索(用\(Q(x,v)=\sum_{y\in son(x),y<x}(Q(y,v)+1)\))),狀態總數是\(O(n)\)的。

比如說計算\(Q(v,mx_v)\),需要用到\(Q(x,mx_v)\);后來又計算了\(Q(x,mx_x)\)。如果\(mx_x>mx_v\),則在鏈\([v\to x)\)中出現了個比\(mx_v\)大的點,那么算\(Q(v,mx_v)\)的時候理應是到不了\(x\)的,矛盾。

其它的也類似一波分析,大概就是枚舉一個點可能存在的兩種不同狀態,在什么條件或者矛盾時兩者才共存。題解說一個點至多有3個。

於是時間\(O(n)\)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM