1. 程式人生 > 其它 >NOIP模擬賽總結&題解

NOIP模擬賽總結&題解

遊記與總結

這場比賽是我做的所有“NOIP模擬賽”中最簡單的了。。。
由於gls反覆叮囑要好好做,於是我就沒有好好做(狗頭),導致被全場吊打。
最開始沒打算打,從szm電腦上看了看題目,發現T1沒看懂T3T4不會,但是10s口胡T2,這時候gls命令我參加,於是我就報名了比賽並開始了被吊打之路。
開場先把T2敲了,但是Fhqtreap居然沒有一次寫對,RP--。切掉T2之後發現T3是個計算幾何,果斷棄掉,然後發現T4是個字串,於是就開始撕烤T4(別問我為啥沒做T1,問就是不會做)。
猜了個結論,感覺很對,於是口胡出 \(O(n^3)\) 的做法,發現只有 \(38pts\),不得已只能繼續想,突然發現由於貢獻是一段區間,所以可以線段樹(沒想到單調棧就是純菜)。
於是莽了一發 \(O(n^2\log n)\)

感覺 \(65pts\) 很穩,於是就打算棄賽了。這時候gls進來給我們解釋T1題意,藉此我提出強烈抗議,請求刪去T1這種垃圾題。
最後在gls的幫助之下,我切掉了T1,到了 \(265pts\),衝上了榜一。
感覺這次比賽自己的一次正確率還行(除了T1那種垃圾題以外),T2T4的正解/暴力都是一次過的。

題解區

T1

垃圾題一道,就是一個讀題題,也沒啥好講的,唯一有意義的就是當模數不為質數時的快速求逆元。
法一:exgcd
\(Ax=1\mod p\) 可以轉化為 \(Ax+Bp=1\),然後就是板子了
法二:尤拉定理
\(Ax=1\mod p\) 可以求得 \(x^{\phi(p)}=1\mod p\)

T2

這場比賽的簽到題,發現前 \(N\) 項和後 \(N\) 項不管怎麼刪一定都有分界點,在這個分界點以前的是刪完後的前 \(N\) 項,以後的是刪完的後 \(N\) 項。
列舉分界點,然後前面保留最大的 \(N\) 個數,後面保留最小的 \(N\) 個數,動態維護。暴力 \(O(n^2)\),用平衡樹/優先佇列都可以優化到 \(O(n\log n)\)

T3

毒瘤計算幾何,思路並不難(cy10秒切了)(cy:你毒瘤吧)
但是(可能是我寫的難看)碼量驚人,大概思路就是這張圖:

顯然在刪掉大凸包上一個點的時候,有用的點之後可能是大凸包上的其他點以及小凸包上的一些點,所以我們先求兩遍凸包把大凸包和小凸包都求出來。
然後我們可以發現,有用的小凸包上有用的點就是大凸包刪除的點左右的點關於小凸包想切點,然後算面積就直接把它拆分成三角形用叉積算面積。
如何找到切點:我們可以發現,在大凸包上的每個點關於小凸包都有兩個切點,如果我們分別考慮的話可以發現切點是單調的,所以我們就雙指標一下分別掃出每個點對應的切點即可。
如何計算每一個區間的面積:先解釋一下區間的面積是啥,那張圖其實不是很完整,因為那兩個點看上去在同一條直線上,如果不在的話我們失去的面積就是三個三角形減去兩個切點之間的面積。
區間的面積我們可以用一個類似雙指標的方法求出,容易發現區間的左右端點都是單調的,所以我們可以直接移動左右端點。
細節:
1.如果建完大凸包後就沒有點,就不用建小凸包了,直接計算即可。
2.如果切點和被刪掉的點關於那兩個點的直線在異側,那麼這個切點根本沒有發揮用處,我們可以直接再大凸包上減掉一個三角形,一定要記得特判這種情況,至於如果用叉積判斷請自行撕烤。
3.在計算小凸包上一個區間的面積的時候一定要記得特判L,R之間的距離有沒有超過凸包的一半。
然後這題就被愉快的切掉了。。。真tm愉快,我寫了一晚上調了一上午(到三點)

T4

很顯然可以發現 \(i\) 能刪掉的點一定是一段連續的區間(這裡的刪掉是指i,i+1,...i+p+1可以被刪的只剩 \(i\)),這個我們可以 \(O(n)\) 遞推出來。
\(f[i]\) 表示 \(i\) 能刪到哪裡,那我的轉移就是看 \(i\) 能不能刪掉 \(i+1\),如果行想話,\(ans\) 跳到 \(f[i+1]+1\),再判斷,直到刪不掉為止。
容易發現對於一個 \(i\) 它只會被最近的能刪掉它的點遍歷,所以是 \(O(n)\)
然後就是可以發現對於每個 \(i\),它能轉移的區間就是 \([i+1,f[i]+1]\),一看就非常線段樹,所以直接做就是 \(65pts\),也就是我的賽場得分。
由於線段樹是沒有前途的,於是我們考慮單調棧,然後就變成了 \(O(n^2)\),有一個 \(n\) 是比較字串的複雜度。
感覺很有前途,我們可以平衡樹優化,變成 \(O(n\log^2 n)\),但是感覺過不去。
由於平衡樹沒有前途,所以我們考慮一隻 \(\log\) 的做法。
發現一個性質,這裡面出現過的每一個字串,要麼是原串的一個字尾,要麼是一個出現過的串的前面再添一個字母。然後我們可以發現,這個形式非常倍增+hash,於是就過了。
\(f,g\) 分別記錄 \(i\)\(2^j\) 步的字串對應的位置和雜湊值,然後直接倍增比較即可。