TOI 2020 初選小題解
昨天看到蛋餅把去年初選的題目都丟到TIOJ了
最近也把pE精神掉了,想說就寫寫看,沒多久就把五題都寫完了
於是就來打個題解吧
雖然只剩下兩天就是ㄌ= =
pA
題解
簽到題,直接做就好了
code
1 |
|
pB
題解
這題我是用重剖寫的,寫完發現單純樹DP也可做,作法其實差不多
重剖
重剖的時候,目標是要求出所有過重心的最長與嚴格次長
方法就是對於重心的每一棵子樹,算出這個子樹的最長與嚴格次長
合併的時候就用類似找樹直徑的做法,維護目前已經跑過的子樹中,最長與嚴格次長的距離
那麼需要更新的答案就會有三種:
- 原本的最長 + 當前最長
- 原本的最長 + 當前次長
- 原本的次長 + 當前最長
這樣做完就結束了~
實作上可能有些細節需要注意,需要好好維護「嚴格」次長
樹DP
樹DP的做法其實跟找直徑很類似
就從原本只維護最長改成多維護一個嚴格次長
合併的方法跟前面重剖一樣,分成三種case更新
好好維護完就結束了
實作上一樣要好好處理「嚴格」的問題
code
1 |
|
pC
題解
事實上認真看題目就會發現兩條重要的式子
所以做法就是
- 用快速冪算模逆元,再算出
- 帶入第二條式子,算出
- 用算出,再用回推出
然後就做完了
code
1 |
|
pD
題解
可以發現只要每個點到原點的直線按照斜率排序好,並將相同斜率的點並在一起
這個問題就會轉換成「給一個環狀序列,問最大的連續區間和」
所以問題只在於
- 要怎麼處理斜率
- 要怎麼算環狀區間和
處理斜率?
問題同於要把點給極角排序
講一下兩種做法
- atan2
內建函數atan2會回傳一個點的極角,用法:
1 | double atan2(int y, int x); |
所以只要事先將x座標為負的點轉180度,再按照atan2的數值排序就好
- cross
首先一樣先把x座標為負的點轉180度,接著假設極角排序完後,順序會是順時針
那麼會成立
所以就直接把這個當作排序的依據,直接做就好
然後因為浮點數是垃圾,所以通常我會用第二種
環狀區間和?
首先先不考慮環狀,把她視為一般的陣列,那麼
環狀最大區間和 = max(陣列的最大連續和, 總陣列和 - 陣列的最小連續和)
前者是不考慮環狀的答案,後者是考慮環狀的答案
所以就用greedy算最大連續和的方法做兩次
再算一算答案就出來了~
code
1 |
|
pE
題解
- 先備知識:AC自動機
首先先把所有的小字串丟到一個AC自動機裡
建完fail陣列之後就能考慮這個dp式:
代表考慮大字串前個字元,且現在位於AC自動機的位置,最大的答案
可能有點抽象,但我不知道要怎麼進一步解釋@@
這樣轉移式的話就會考慮第個字元能放甚麼字元,然後用類似AC自動機match的方式,計算加入字元後,AC自動機會移動到的位置,並加上新的AC自動機位置的小字串價值總和
複雜度會是
code
1 |
|