1. 程式人生 > 實用技巧 >【NOI2020遊記】NOI如何拿到部分分(詳細揭祕)

【NOI2020遊記】NOI如何拿到部分分(詳細揭祕)

背景

省選day1T1爆零的情況下意外混進了省隊(D類)。

做了往年的題,感覺自己實力確實不太夠。比如說,2018年的簽到題(kruskal重構樹)和2019年的簽到題(斜率優化),憑我自己的能力都無法做出(“思維”和“演算法的積累”兩方面來講,都是題目難度>我的水平)。

2016和2017年的題,我倒是能做出一兩道(比如2016的Day2T1“區間”和2017Day1T2的蚯蚓排隊),但是也有簽到題我做不出來(比如2016的Day1T1“優秀的拆分”我只會90分;2017的Day2T1“遊戲”我只想到先\(3^d\)列舉再2-SAT,看了題解才知道可以優化為先\(2^d\)再2-SAT)。

上述列舉的這些都是當年的“簽到題”,更不必說更難的題了,我只能打打暴力。

事實上,按照往年的情況,如果做出了這些簽到題,暴力不掛分的話,就能拿到銀牌了。不過壞訊息是簽到題似乎一年比一年難了...


Day-1(8.16),Day0(8.17),大家都在一起快樂狼人殺。然後都被李曙查水錶了。


試機的題是:NOI2019 Day1T2機器人,NOI2019 Day1T3 序列,NOI2019 Day2T3 I君的商店。

試機後,大家聊天的句式都是:“哎,明天會不會要考xxx啊,如果考xxx我就沒了啊...。我沒了啊...”。其中“xxx”可以是任何一種我聽都沒聽過的演算法,可能已經遠高於歷年NOI的難度了,我不知道大家為什麼都要這麼說...。是為了搞別人心態嗎?還是為了顯示自己聽過別人不知道的演算法呢?

哎,可能大家只是習慣性地假...


晚上李曙給我囑咐了幾句:兩天都會各有一道簽到題,爭取拿到70分。剩下的題每道題打30分暴力。每天130分,就能穩拿Ag了。

正好我的目標也是拿到Ag。所以對這番分析深以為然。

Day1

\(50+32+40=122\)

昨晚10點就睡了,半夜4:19醒了一次,又睡到6:40自然醒起床。可以說睡眠是很充足的,考試時精神也很好。上午考試前李曙給我們拍了個合照,本來我和djq站在一起,然後李曙一波安排,我就和dxm換了位置(你品,你細品 /滑稽)。


本著先在簽到題拿高分的想法,我先看T1。是個圖論題,而且沒什麼想法(我好像經常對圖論題毫無思路...,無論這題本身是什麼難度...)。我想是不是以1為根,搜出dfs樹,然後看有沒有環?然後對環做揹包?看上去很奇怪,於是先看T2。

T2雖然題面很長,但看下來倒是覺得非常自然,也很好懂。看到前幾個點\(m\)很小,一下就能想到做容斥。我粗略地以為時間複雜度是\(O(2^m\cdot \text{poly}(m))\),然後以為自己能拿到40分。然後就繼續去看T3了。此時時間大概是8:18。

T3是個“很多維數點”...。看起來是個資料結構題。\(O(nm\log n)\)是很簡單的(考完後聽別人一說才想到,做個二維字首和就變成\(O(nm)\)了。不過得分是一樣的,所以也不重要,只是體現了我智商很低...)。部分分A(\(c_1=1,c_2=n\)),我想了想,離線?樹套樹?分治?貌似都不對。好像可以莫隊,不過是\(O((n+m)\sqrt{n}\log {n})\)的,不知道能不能過\(10^5\)...。沒太多想,就先去寫T2暴力了。


先寫了個\(O(2^n)\)暴力。因為後面不管些什麼都可以用它拍。寫完這個9:06。然後繼續寫“\(O(2^m\cdot \text{poly}(m))\)暴力”。發現自己一開始想錯了,這個暴力並不是\(O(2^m\cdot \text{poly}(m))\)而是\(O(2^m\cdot n)\)。可能只能拿20分,這就要低於李曙給我定的計劃了。於是又進一步想想,發現可以用樹鏈剖分優化到\(O(2^mm\log^2n)\),期望拿到32分。雖然比之前以為的40分低了一些,但還是達到了李曙說的30分。

T2似乎後面還能再搞一個樹形DP:\(dp[i][j]\)表示第\(i\)個點向上的前\(j\)條邊裡必須至少有一個重要邊。我不太清楚它是\(O(n^2)\)還是\(O(n^3)\)的,不過應該還能再拿到一些分。但是看分不多我又不是很確定,就先沒寫這個。決定穩妥一點,先寫T1,T3暴力,最後再寫這個DP。此時9:52(畢竟寫樹鏈剖分還是要花不少時間的)。


再看T1,首先發現我原來那個“找出所有環然後做揹包”的思路徹底假了,因為環的數量可以是指數級的。不過很快驚喜地發現可以直接在圖上做DP:設\(dp[i][j]\)表示第\(i\)天到達節點\(j\),能獲得的最大收益。轉移直接枚舉出邊即可。時間複雜度\(O(T(n+m))\)。可以得到40分。然後又發現下面兩點:圖是一個環的部分分很簡單,於是寫了。

現在是10:44,T1總共有50分。感覺不錯,先去上了個廁所。此時想到,\(T\)這麼大,應該是矩陣快速冪。不過10秒鐘後,我把自己否決了。我在草稿紙上寫下:矩陣快速冪(x):max不能矩乘。考完試才知道是我naive了。哎,完美地記錄了我的無知...


雖然T1沒拿到預期的70分,不過我看沒有除快速冪外的其他思路,就沒有繼續糾結,轉而去寫T3部分分。\(O(nm\log n)\)的部分分就是用樹狀陣列維護,非常好寫。部分分A,我思考以後發現分治、樹套樹,這些似乎都不靠譜,於是嘗試去寫sqrt log的莫隊。寫完以後一測大樣例,沒過!我又對拍了小資料,才發現是我樹狀陣列寫錯了。簡而言之就是,改變了不該改變的引數,偷懶沒有使用替身變數導致的錯誤(都是平時習慣不好,如果函式都寫const int& 就沒這個問題了)。又自己造了一組\(10^5,2\times10^5\)的隨機資料,實測3.2s左右,感覺能過(下午查分發現只跑了1.8s)。

搞完這些,已經12:15了。這時候我發現一個大問題,T1的對拍的時候,因為一些不熟悉linux系統而導致的錯誤,我的程式其實沒拍上...。修正了這個錯誤後,我重新對拍了T1,T2。T2過拍了。T1卻沒有過。(一開始搞錯了,以為兩個都沒有過。反正那2分鐘還挺刺激的)。好在發現T1是個小錯誤,改了就好了。

12:40左右試圖開始寫T2的樹形DP部分分。但是時間不夠了,沒寫完。最後就檢查了一下檔案啥的,提交提交,就結束了。


嗯。整個過程大概就是這樣了。雖然分比同學低不少,但是沒有掛分。又想到我的同學都是集訓隊水平,所以我感覺,也還行?然後李曙又笑嘻嘻地說不錯不錯(雖然他和誰都這麼說),所以我還挺開心的。


總結反思?還沒細想,以後再更吧。