1. 程式人生 > 其它 >2021-7-14 考試總結

2021-7-14 考試總結

打得比較拉跨,最簡單那題沒過

a

看了一會發現是經典的劃分數問題,過掉的速度略慢。

主要問題有兩個:

  • 對經典問題不是特別熟悉,思考了較長時間。

  • 寫程式碼時小細節出現問題,陣列開小導致 \(\rm RE\)。以後如果輸出與程式碼不符可以考慮是否 \(\rm RE\) 陣列越界等。

b

大概做了較長時間,這是一道比較難的題,難度應該和 \(\rm NOIP2020 \ T4\) 相當。

但依然在程式碼實現上存在問題,例如:

  • 變數寫錯位置。

  • 沒有想清楚細節就開始急著寫程式碼。

尤其是第二點,需要長記性想得很清楚再碼。

c

考試的時候沒怎麼做,沒有太多想法。

事實上如果 \(b, d\) 程式碼實現時間簡短,可以拿到這題 \(40\)

分暴力。

d

其實應該是這場考試最簡單的題,但因為位置在 \(\rm T4\) 所以沒有過掉。

本場考試中這題出現的問題最大,主要為如下幾點:

  • 選擇了一個細節非常繁雜的做法,一般而言正解應該不會過於繁雜,因此當做法很繁雜而且想不太清楚時需要更換做法。

  • 程式碼實現時沒有想清楚就直接開始寫,這個問題一定要牢記。


今天題目的具體總結:

b

不難發現,這個問題本質上就是:將喜歡看成左括號,不喜歡看成右括號,不確定的可以填任意的括號,問有多少個區間可能出現完美匹配。

首先,我們可以得到一個暴力做法:列舉每個區間,算出需要填的左括號數量,右括號數量,顯然左括號越往前填越優,複雜度:\(\mathcal{O}(n ^ 3)\)

對於此類問題,我們一般需要使用形式化的描述給出區間合法的充要條件,直接尋求不好找,考慮找一些必要條件:

我們首先先讓所有不確定的位置填左括號,將左括號看作 \(1\) 右括號看作 \(-1\),令 \(A_i\) 為左右括號權值的字首和,\(B_i\)\(1 \sim i\) 中不確定的位置數量,那麼有如下三個必要條件:

  • \(A_r - A_{l - 1} \equiv 0 \pmod{2}\)
  • \(\forall i \in [l, r], A_i - A_{l - 1} \ge 0\)
  • \(\forall i \in [l - 1, r], A_r - 2 \times (B_r - B_i) \le A_i\)

可以發現,同時滿足這三個條件時是充分的!(證明不難)

於是問題就變為求滿足上面三個條件的點對 \((l, r)\) 的數量,此時不難得到 \(\mathcal{O}(n ^ 2)\) 暴力。

不難發現第一個問題可以先確定奇偶性再對相同奇偶性的點拿出來分別做即可,於是這條限制可以忽略。

考慮分治,回顧兩個條件:

  • \(\forall i \in [l, r], A_i \ge A_{l - 1}\)
  • \(\forall i \in [l - 1, r], A_r - 2 \times B_r\le A_i - 2 \times B_i\)

先求出不考慮跨區間的情況下滿足 \(1, 2\) 條件的左右端點。

再考慮跨區間的情況,將詢問掛在 \(l\) 上,這就是一個掃描線,於是可以輕鬆做到 \(\mathcal{O}(n \log ^ 2n)\)

考慮如何卡掉一個 \(\log\),對於排序部分,我們在歸併排序的時候記錄每個分治區間的排序陣列即可。

對於掃描線部分,我們按照第二個條件做掃描線,以第一個條件建樹狀陣列查詢。

此時我們發現這等價於按照左端點從大至小排序,右端點從大至小掃過來。

考慮左端點左移時查詢位置的變化:\(|A_{l - 1} - A_l| \le 1\),於是我們不用樹狀陣列維護,直接維護一個桶,每次可以暴力移動指標統計,這樣區間統計的複雜度就是線性的了。

於是這樣的複雜度就是 \(\mathcal{O}(n \log n)\) 的了。

c

知道了做法,但目前不是特別清楚為什麼要這麼做,先鴿。

GO!