『板刷 AGC』[AGC016] A~E 做題記錄

Supor__Shoop發表於2024-10-09

遠古的一場 AGC,能夠把前四題做出來,後面兩個看了題解還是隻會 E,F 是最近才拉過的一道題,但我不會,沒辦法我還是太菜了。。

A: Shrinking

人機簽到題。

先列舉我們最終保留的字元 \(c\),然後我們就按照題意模擬一邊,每次從 \(s\) 更新到新的字串 \(s'\) 的時候,我們希望得到的 \(s'\) 中有儘可能多的 \(c\) 字元,因此如果 \(s_{i},s_{i+1}\) 中存在 \(c\),就令 \(s'_i\leftarrow c\);否則就隨機選,因為這一步無論怎麼選都不會影響到後面的字串。

記錄 \(c\) 這個字元的答案,比完 \(26\) 個字元的答案就行了。

時間複雜度 \(O(|s|^2)\)

B: Colorful Hats

人機分析題。

分析一下性質,設 \(col_i\) 表示 \(i\) 帽子的顏色,我們任取兩個不同的帽子 \(i,j\),設剩下的 \(n-2\) 個帽子的顏色集合為 \(S\)。我們考慮根據 \(i,j\) 的顏色與 \(S\) 之間的關係進行討論:

  • \(col_i,col_j\) 都不屬於 \(S\),那麼根據題意顯然有 \(a_i=a_j=|S|+1\)
  • \(col_i,col_j\) 中恰好有一個屬於 \(S\),不妨設 \(col_i\in S,col_j\notin S\),則有 \(a_i=|S|+1,a_j=|S|\)
  • \(col_i,col_j\) 都屬於 \(S\),那麼就有 \(a_i=a_j=|S|\)

因此 \(a\) 中元素的極差應該在 \([0,1]\) 中。

接著,我們就對這個極差進行分討:

  • 若極差為 \(0\)。則每個帽子的顏色最多隻有兩種構造方案,一種是每個帽子顏色獨一無二,一種是滿足每種顏色在所有帽子中至少出現 \(2\) 次。因此帽子中出現的顏色個數有兩種取值範圍,一種是 \([n,n]\),一種是 \([1,\lfloor\frac{n}{2} \rfloor]\)。由此,我們可以推出 \(a_1\) 的取值,顯然有 \(a_1\in [1,\lfloor\frac{n}{2} \rfloor]\cup[n-1,n-1]\),後面不取 \([n,n]\) 是因為要排除 \(i\) 本身的顏色。

  • 若極差為 \(1\),設 \(p,q\) 分別為 \(a\) 中的最小值和最大值,\(s_1,s_2\) 分別為 \(a_i=p\)\(a_i=q\)\(i\) 的個數。根據一開始我們分析:\(a_i-a_j=1\Rightarrow col_i\in S,col_j\notin S\)。列舉所有的 \(a_i=q\)\(i\)\(a_j=p\)\(j\) 代入這個條件,則我們能夠確定 \(a_i\) 較小的 \(s_1\) 個帽子的顏色\(n\) 個帽子中獨一無二,進而得到顏色總數固定為 \(p+1\)。而對於一個 \(a_i=q\)\(i\),必然存在另一個帽子與其顏色相同。因此我們只需要判斷顏色總數的範圍,即 \(p+1> s_1\)\(p+1-s_1\in [1,\frac{s_2}{2}]\cup [s_2,s_2]\)。其中 \(p+1-s_1\) 表示 \(a_i\) 較大的帽子顏色種類數量。

因此我們對於上面兩種情況,判斷 \(a_1\) 或者 \(p\) 的取值就行了。

C: +/- Rectangle

人機構造題。

要使得每個 \(h\times w\) 的子矩陣內元素和為負數,且整個矩陣內元素和為正數,則我們肯定是讓每個 \(h\times w\) 的子矩陣元素和儘可能大,最好取到 \(-1\)

我們可以這樣構造,對於所有滿足 \(i\bmod h=1\)\(j\bmod w=1\) 的座標 \((i,j)\),我們在 \((i,j)\to (i+h-1,j+w-1)\) 這個矩陣中全部放入相同的 \(v\),然後把 \((i+h-1,j+w-1)\) 這個位置的元素改為 \(-(h\times w-1)\times v-1\)。這樣每個 \(h\times w\) 的子矩陣內的元素和都為 \(-1\)

\(x=H\bmod h,y=W\bmod w\),若 \(x=0,y=0\),則顯然無論怎麼構造都是無解的。對於其它的所有情況,我們把 \((1,1)\to (H-x,W-y)\) 這一部分的子矩陣拎出來,它內部的元素和為 \((-1)\times \frac{H-x}{h}\times \frac{W-y}{w}\),而除了這個子矩陣外,我們剩下的元素就一定是正數,因為我們的構造方案中是把負數放在了 \((i+h-1,j+w-1)\),除非是 \(x=0,y=0\),不然你在剩餘部分是不可能取到這個負數的。

最後我們就來考慮 \(v\) 該怎麼取值,在最劣情況下,\((1,1)\to (H-x,W-y)\) 之外的元素個數會取到 \(\min(H,W)\),因此我們只需要滿足:

\[v\times \min(H,W)+(-1)\times \frac{H-x}{h}\times \frac{W-y}{w}\geq 0 \]

\[-(h\times w-1)\times v-1\geq -10^9 \]

用一個程式檢驗一下可以知道 \(v=1000\) 是萬能解,按照 \(v=1000\) 進行構造就行了。

D: XOR Replace

人機結論題。

假定 \(a\) 始終保持為初始的序列,\(s\) 表示當前序列。設初始 \(a\) 的異或和為 \(x_0\),將要修改的位置為 \(i\),我們發現一次操作後 \(s_i\) 變成了 \(x_0\),而當前異或和就先去掉 \(a_i\),再重新異或一個 \(x_0\),即 \(x_0\bigoplus a_i\bigoplus x_0=a_i\),設第二次操作是在 \(j\) 上,則有 \(s_j\leftarrow a_i\),當前異或和變成 \(a_i\bigoplus s_j\bigoplus a_i=s_j\),以此類推。

綜上,我們發現操作的本質就是在 \(a\) 的末尾加上一個 \(x_0\),然後弄一個操作序列 \(S=\{t_1,t_2,t_3,\dots,t_m\}\),表示第 \(i\) 次操作為交換 \(a_{t_i},a_{t_{i+1}}\) 的值。最後就是讓 \(a\) 的前 \(n\) 項與 \(b\) 相同。

於是判無解的方式就很明顯了,就是看 \(b\) 元素的可重集是否是 \(a\) 元素的可重集的子集。

當然,如果有 \(a_i=b_i\),那我們就忽略掉這個 \(i\) 就行了,這個一定不會影響我們的答案。

先考慮一個粗略的二分圖建圖思路,上部為 \(a\) 的點,下部為 \(b\) 的點,對於 \(a_i=b_j\) 連一條有向邊,從上部的 \(i\) 連向下部的 \(j\),邊權為 \(1\),由於每次要用上一次被操作的位置去替換別人,因此我們還要對每個 \(i\) 從下部的 \(i\) 連向上部的 \(i\),邊權為 \(0\)。我們的目的就是求最短的一條從 \(x_0\) 所在點開始的路徑使得下部的所有點都被經過。

但是這樣肯定是難以實現的。我們發現對於一個 \(i\) 可能會有多個 \(j\) 滿足 \(a_i=b_j\)。不過我們可以思考這些連邊的本質,其實就是權值替換。題目要求的是讓權值對應,而我們的暴力連邊還額外承受了具體的下標這一元素,我們大可不必考慮到底是哪些下標的數在交換。因此我們更改連邊策略,在值域上進行連邊,每次從 \(b_i\) 連向 \(a_i\),表示有一個位置要用初始序列中的一個 \(b_i\) 去替換掉它的 \(a_i\),則一條路徑就表示若干個數之間交換的傳遞性,因此我們只需要從 \(x_0\) 開始走,找一條經過所有邊的路徑。

不過仔細想想就會發現我們連出來的圖可能不是一個連通塊,這很好解決,我們只需要等 \(x_0\) 所在連通塊處理之後,直接花費 \(1\) 的代價移動到另一個連通塊就行了,其本質就是處理了 \(x_0\) 連通塊的答案之後,我們用多出來的數去處理另一個連通塊,由於這個數在連通塊中不存在連邊,它就不會對答案造成多餘影響。

由於每條邊都會被經過一次,且除開無解情況後每個連通塊必然存在一條尤拉回路,我們只需要關心有多少個連通塊。直接用並查集維護一下好了。

最後的答案就是連邊數量加連通塊數量減一。

E: Poor Turkeys

人機暴力題。

挺妙的,我根本想不到,我是人機。

首先可以思考到底怎麼操作才能使得一隻火雞 \(i\) 留下來。我們把每個人選擇的兩個火雞 \(x,y\) 進行連邊,如果存在一個 \(j\) 使得 \(i,j\) 之間有連邊,那麼我們肯定就要殺掉 \(j\),但是這樣的前提是 \(j\) 能撐到這條邊連線的時刻,因此我們要考慮如何操作才能使得 \(j\) 在這條邊連線之前存活下來。這樣,問題就形成了一種遞迴形式。

具體地,我們要讓 \(i\) 最終存活,則對於每一條連線了 \(i\) 的邊 \((i,x)\),我們必須要保護好 \(x\),不然等到 \((i,x)\) 這條邊時,因為 \(x\) 已經被吃了,那 \(i\) 就必然被吃。於是目的就變成了保護這些 \(x\),以此我們得到所有的用來保護 \(i\) 活到最後的火雞,設其集合為 \(S_i\)

因此我們考慮時光倒流,從後往前列舉時間 \(t\),對每個火雞 \(i\) 維護集合 \(S_i\),表示為了使 \(i\) 存活,只考慮 \(t\) 這個時間之後的邊我們需要保護的火雞集合,初始有 \(S_i=\{i\}\)。對於當前時間 \(t\),設這個時刻的連邊為 \((x,y)\),我們思考如何修改每一個 \(S_i\)

如果對於一個 \(i\),有 \(x\in S_i\wedge y\in S_i\),則兩者之間必然要選擇一個被吃掉,即兩者必然有一個不能被保護,那麼 \(i\) 就一定不能活到最後。如果 \(x,y\) 中恰好有一個屬於 \(S_i\),不妨設其為 \(x\),由於我們需要保證 \(x\) 一直活到 \(t\) 之後的某條連邊,那麼此時此刻就只能去吃掉 \(y\),因此在 \([1,t-1]\)\(y\) 必須活著,不然此刻 \(x\) 必然會被吃掉,於是我們把 \(y\) 放進 \(S_i\) 裡面。

最後我們就要判斷 \(i,j\) 是否可以同時活到最後,如果 \(i,j\) 有一個被確定活不到最後那就肯定不行。對於其它情況,我們只需要列舉另一隻火雞 \(k\),如果有 \(k\in S_i\wedge k\in S_j\),則兩者不能同時存活。用歸納法來證明一下:

證明:

\(f(k)\) 表示若 \(k\in S_i\wedge k\in S_j\)\(i,j\) 能夠同時存活。

各自找到兩條邊 \((k,x),(k,y)\) 使得 \(x\in S_i\wedge y\in S_j\),且在上述列舉過程中 \(k\)\(x,y\) 更晚放入對應的集合。

  • \(x\not=y\),不妨設 \((k,x)\)\((k,y)\) 之前被連線,則此時 \(k\) 會為了 \(x\) 而提前犧牲,從而不能保護後來的 \(y\),那麼 \(S_i,S_j\) 中必然有一個元素不能被保護,因此有 \(f(k)=0\)

  • \(x=y\),則 \(f(k)=f(x)\)。由於最終必然會遞迴到一個點 \(p\) 使其連線了 \(i\)\(j\),因為 \(i\not= j\),此時根據第一個部分必然有 \(f(p)=0\),從而所有遞迴下去的 \(f(k)=0\)

根據這個結論直接暴力列舉就行了,時間複雜度 \(O(nm+n^3)\)