ABC363 DEF 題解

DengStar發表於2024-07-22

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

題目連結

依題意,可以得到一個地塊沉沒所需的兩個條件:

  1. 該地塊的海拔小於等於海平面。
  2. 該地塊臨海,或者與某個已沉沒的地塊相鄰。(下面簡單地把這個條件成為“臨海”)

第一個條件中,海拔是一開始就確定的。而第二個條件中,一個地塊什麼時候臨海,是動態的。並且一個地塊只要在某個時刻開始臨海,它在之後的時刻就會一直臨海,直到沉沒。

我們可以用優先佇列維護地塊的“臨海”狀態——把所有臨海的地塊都加入優先佇列中。具體地,在優先佇列中,我們按地塊的海拔從小到大排序。每次海平面升高,就彈出隊首的所有海拔不超過海平面的地塊,同時計數以得到答案。如果某個地塊沉沒了,就把它的所有相鄰地塊都加入到優先佇列中(如果這些地塊還未被加入),表示這些地塊也開始臨海。

在這一過程中,需要記錄每個地塊是否被加入到佇列中,以防重複統計。同時,由於每個地塊只會被加入一次,所以時間複雜度為 \(O(n^2 \log n^2)\)(這裡的 \(n^2\) 指題目中的 \(H\times W\))。

參考程式碼

F - Palindromic Expression

題目連結

賽時沒思路,賽後看了題解才知道搜尋/fn(這麼大的數除了搜尋還能是什麼??)

觀察發現,如果一個數 \(n\) 能用迴文表示式表達,有三種情況:

  1. n,如果 \(n\) 本身就是迴文數。
  2. x*rev(x),其中 rev(x) 表示 x 的倒序書寫。
  3. x*(expression)*rev(x),期中 (expression) 也是一個迴文表示式。

實際上,第二種情況可以不必討論,因為可以把它看作 x*1*rev(x),這樣就歸到了第三種情況中。

於是我們可以設計出函式 \(f(n)\),它返回值為 \(n\) 的迴文表示式。如果不存在這樣的表示式,就返回空串。它的工作原理如下:

  1. 如果 \(n\) 是迴文數,直接返回 \(n\)

  2. 否則,列舉 \(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))\)

參考程式碼

相關文章