ABC363 DEF 題解
前情提要:賽時過了 ABCE。
D - Palindromic Number
題目連結
其實賽時已經看出了一些性質,但沒想完做法,賽後看題解才發現這麼簡單/fn
首先,為了方便,我們不把 \(0\) 視作迴文數(因此需要特判一下 \(n = 1\) 的情況)。
下面要證明:\(d\) 位迴文數有 \(10^{\left\lfloor \frac{d+1}{2} \right\rfloor} - 10^{{\left\lfloor \frac{d+1}{2} \right\rfloor} - 1}\) 個。這裡,我們定義 \(d\) 位不含前導零迴文數的數量為 \(\operatorname{palin}(d)\),則欲證的命題為 \(\operatorname{palin}(d) = 10^{\left\lfloor \frac{d+1}{2} \right\rfloor} - 10^{{\left\lfloor \frac{d+1}{2} \right\rfloor} - 1}\)。
(這個數列在 OEIS 上面標號為 A050683)
證明這個結論的要點在於:如果一個數是迴文數,它就可以由它的“前一半”數位確定。例如,如果已知一個 \(8\) 位迴文數的前 \(4\) 位是 \(1827\),那麼這個迴文數就一定是 \(18277281\)。所以 \(d\) 位迴文數的個數,實際上就是“前一半”數位能產生的數的個數。下面以 \(d\) 為偶數來討論。
如果 \(d\) 是偶數:\(d\) 的前一半數位有 \(d / 2\) 位,而 \(d / 2\) 位的整數有 \(10^{\frac{d}{2}}\) 個,但這些整數有的包含了前導零。包含了前導零的整數的數量,可以看作確定第一位為 \(0\),剩下 \(d/2 - 1\) 位產生的整數的數量。這個數量是 \(10^{\frac{d}{2} - 1}\)。綜上所述,\(d / 2\) 位的不含前導零的整數的個數為 \(10^{\frac{d}{2}} - 10^{\frac{d}{2} - 1}\)。
\(d\) 為奇數的情況依法類推。總之,如果把奇偶的表示式合併,就得到了欲證的式子:\(\operatorname{palin}(d) = 10^{\left\lfloor \frac{d+1}{2} \right\rfloor} - 10^{{\left\lfloor \frac{d+1}{2} \right\rfloor} - 1}\)。
得到這個結論以後,我們列舉位數 \(d\),不斷從 \(n\) 減去 \(\operatorname{palin}(d)\),直到 \(n \le \operatorname{palin}(d)\),這就說明欲求的迴文數的位數是 \(d\),並且它是第 \(n\) 個 \(d\) 位迴文數(這裡的 \(n\) 指的是已經減去了位數小於 \(d\) 的迴文數個數的 \(n\),下同)。
再次運用迴文數的性質:迴文數可以由它的前一半數位決定。對於 \(d\) 位迴文數,它的前一半數位就是前 \(\left\lfloor \frac{d+1}{2} \right\rfloor\) 位。所以我們只要求出第 \(n\) 個不含前導零的 \(\left\lfloor \frac{d+1}{2} \right\rfloor\) 位數即可,這點不難實現。求出以後,把它翻轉並拼接到自己的末尾,所得的就是欲求的迴文數。
參考程式碼
E - Sinking Land
題目連結
依題意,可以得到一個地塊沉沒所需的兩個條件:
- 該地塊的海拔小於等於海平面。
- 該地塊臨海,或者與某個已沉沒的地塊相鄰。(下面簡單地把這個條件成為“臨海”)
第一個條件中,海拔是一開始就確定的。而第二個條件中,一個地塊什麼時候臨海,是動態的。並且一個地塊只要在某個時刻開始臨海,它在之後的時刻就會一直臨海,直到沉沒。
我們可以用優先佇列維護地塊的“臨海”狀態——把所有臨海的地塊都加入優先佇列中。具體地,在優先佇列中,我們按地塊的海拔從小到大排序。每次海平面升高,就彈出隊首的所有海拔不超過海平面的地塊,同時計數以得到答案。如果某個地塊沉沒了,就把它的所有相鄰地塊都加入到優先佇列中(如果這些地塊還未被加入),表示這些地塊也開始臨海。
在這一過程中,需要記錄每個地塊是否被加入到佇列中,以防重複統計。同時,由於每個地塊只會被加入一次,所以時間複雜度為 \(O(n^2 \log n^2)\)(這裡的 \(n^2\) 指題目中的 \(H\times W\))。
參考程式碼
F - Palindromic Expression
題目連結
賽時沒思路,賽後看了題解才知道搜尋/fn(這麼大的數除了搜尋還能是什麼??)
觀察發現,如果一個數 \(n\) 能用迴文表示式表達,有三種情況:
n
,如果 \(n\) 本身就是迴文數。x*rev(x)
,其中rev(x)
表示x
的倒序書寫。x*(expression)*rev(x)
,期中(expression)
也是一個迴文表示式。
實際上,第二種情況可以不必討論,因為可以把它看作 x*1*rev(x)
,這樣就歸到了第三種情況中。
於是我們可以設計出函式 \(f(n)\),它返回值為 \(n\) 的迴文表示式。如果不存在這樣的表示式,就返回空串。它的工作原理如下:
-
如果 \(n\) 是迴文數,直接返回 \(n\)。
-
否則,列舉 \(n\) 的因子 \(d\)。如果 \(\operatorname{rev}(d) \times d\) 也是 \(n\) 的因子,那麼 \(n\) 就有可能由
d*(expression)*rev(d)
表達,其中(expression)
是一個值為 \(n / (\operatorname{rev}(d) \times d)\) 的迴文表示式。於是遞迴求解 \(f(n / (\operatorname{rev}(d) \times d))\) 即可。顯然,在列舉因子 \(d\) 時,我們只需要嘗試小於 \(\sqrt{n}\) 的整數。原因如下:如果存在一個大於 \(\sqrt{n}\) 的整數 \(d\),使得 \(d \times \operatorname{rev}(d)\) 是 \(n\) 的因子,那麼 \(\operatorname{rev}(d)\) 一定小於 \(\sqrt{n}\) 並且也是 \(n\) 的因子,而這樣的數我們肯定已經列舉過了。透過這個限制,我們就可以大大降低時間複雜度。
需要注意的是,由於表示式中不能含有 \(0\),所以要判斷 \(d\) 中是否有 \(0\)。
時間複雜度分析:還不會,但官方題解說上界是 \(O(\sigma^2(n))\)。
參考程式碼