NOI2020 游記
兩位捧杯爺鎮樓。
背景
省選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部分分。但是時間不夠了,沒寫完。最后就檢查了一下文件啥的,提交提交,就結束了。
嗯。整個過程大概就是這樣了。雖然分比同學低不少,但是沒有掛分。又想到我的同學都是集訓隊水平,所以我感覺,也還行?然后李曙又笑嘻嘻地說不錯不錯(雖然他和誰都這么說),所以我還挺開心的。
Day2
\(0+20+5=25\)
昨天聽說比銀牌線略差一點。那今天要加把勁了。我計划不惜一切代價猛干T1,其實這個計划無比正確,只可惜我沒有堅持執行。后面我們會分析到原因。
先來看看比賽過程。開場看T1。理解了題意后,最開始以為是網絡流,但是立即就發現不對。
於是嘗試某種貪心。一種想法是,可以將所有原料排好序,然后最大的和最小的匹配。其實這就是\(m=n-1\)時的正解,並且可以修改后得到本題正解。但我只是憑空猜出來這個貪心,而沒有注意到\(m\)與\(n\)的關系。所以我手玩一下小樣例,發現最后一個點過不去,就放棄了這種做法(於是就遠離正解了...)。
后來又猜了一種貪心,嘗試枚舉一個斷點,斷點左邊的第一個和右邊的第一個配,第二個和第二個配,以此類推...。不過這個好像也不太對。我寫了一半放棄了。這里有一點心得,感覺不太對的算法基本寫着寫着都會假掉。因為如果是正解,你一定可以想好每一個細節,或者說,它的每一個細節都是“經得起檢視的”。如果你自己對這個算法都“支支吾吾”,無法實現出細節,那它肯定就不對了。
此時大概一個小時過去了。因為T2題面太長,T3看起來又像是我不擅長的圖論題,於是決定繼續看T1:寫T1的暴力。最朴素的想法是,枚舉\(m\)道菜里每道菜用了哪兩種原料(或者第二種不用)。那么枚舉量是\(n^m\cdot (n+1)^m\),似乎只能過最小的\(n,m\leq 4\)的點。並且,枚舉完之后還無法計算出每種原料具體給每道菜分配多少,可能還需要高斯消元?我沒細想,但這個作為最低檔的部分分也太離譜了,於是就沒寫。
然后我又想了一個暴力,它基於的猜想是,所有可行的方案,都可以被描述為\(n\)種原料的一個排列,按這個排列排好后,依次把原料倒入每一道菜就能得到這個方案。朴素枚舉所有排列的話,復雜度是\(O(n!\cdot (n+m))\)的,看起來可以通過\(n,m\leq 10\)的分,並且看起來很有優化前途:既然是排列,那么我們可以隨機交換兩項,看是否變優,也就是用模擬退火算法來做。
於是我立刻動手寫了這個枚舉全排列的暴力。可惜它過不了第二個樣例...。我仔細想了一下,它確實是不對的,只要有一種\(d_i\)很大的原料,這種構造方式就不一定能得到最優方案了。於是,剛剛想到的所有優化前途都泡湯了...
此時已經10:00左右,我決定放棄T1,去看看T2, T3。
T2題面雖然長,但還是好懂的。
本題顯然是需要結論的,否則怎么面對“無窮”這個概念呢?計算機的算力再強,如果只用朴素的枚舉,也無法對抗無窮啊!
然而我就是一直沒想到什么靠譜的結論。可能是我的分析能力還不太夠;也可以說我對本題,只是看懂了定義,卻對這個定義沒有一個感性的理解,導致想了很久,還是徘徊在原點...
好在根據數據范圍,判樣例可以拿到12分,這可比T1的暴力分好拿多了。我基於這個樣例,瞎寫了一些東西。我猜測,一組樹可行,當且僅當存在某一層,滿足:任意一個“這層所有節點的子集”,都能對應為,某棵樹在這一層上的所有葉子節點。
然后這個結論,我也不知道是太強了還是太弱了,既不知道充分性也不知道必要性。反正我只知道它能過小樣例(\(1\sim 4\))但是過不了其他樣例。但既然能過樣例\(1\sim 3\),那得分肯定不會低於12分,於是就交了這個。事實上它得了20分。
寫完T2這一通東西,時間還剩最后一個小時了。我趕緊去看T3。我以前完全不知道弦圖這個概念,也不知道任何性質。后來知道,A部分分是直接輸出最短路,但這個可能也不太好猜?反正我在考場上完全沒想到。
我看到部分分B是以一條鏈為主干,我以為可以做一個,類似於在序列上DP的東西。寫了一下,發現假了,完全不對。
最后時間不夠了,只能全刪掉,改成輸出-1
。得到了5分。
於是這場比賽就遺憾的結束了。最后T1的那個全排列假做法也沒來得及改,交上去得了0分。我全場就暈頭暈腦地寫了個T2假結論,還有T3輸出-1
騙了5分。
總結分析
結局:銀牌線\(274\)。我\(247\) Cu了。
Day1,主要還是打得太保守了。可能是什么都要拍,就導致進展非常慢。但是我確實拍出來一個小錯誤(T1),並且最后我也沒掛分,打滿了我自己認為的暴力,所以說明對拍還是很重要的。
那么我的分析是,是否可以盡可能先想到更高的分,再動手開始寫。這樣寫完正解,還是寫個小暴力來拍,就比我現在的情況要好。我現在是先寫個40分暴力,再寫個10分暴力和它拍,然后如果再要寫正解,那可能一共就要寫3個程序了,有點來不及。
下次應該嘗試一下,先硬想一個小時,想出正解(或者較高部分分)的思路,這樣就可以省去“40分暴力”的這個環節。
當然,這與我水平的提高,也就是能不能想到,也是有很大關系的。
我們事后來看Day2,其實大家分都很低。主要的區分度就在T1,能不能做出來或者拿到較高的分。
這個題的特點是,沒留什么純暴力分,沒法爆搜或者枚舉。逼着你想結論,哪怕只是一個部分的結論(比如\(m=n-1\)的那個)。當然,如果你只是純靠猜(和我一樣),那你一定會因為樣例而懷疑自己的結論。所以說到底還是要靠分析。
如果從事后的角度分析,我就算Day2爆零也能拿Cu,結果並不會變差。而如果專注干T1,則有機會想出正解,拿到銀牌。所以我的策略可以說,傻了。當然,這里面既有運氣的成分,也有不會判斷題目難度而導致的考場決策力不行。
綜合這兩天來看,主要的問題都是:中等題做不出來。這里“中等題”,指的就是Day1T1,Day2T1,這種NOI比賽里的“簽到題”。但客觀地講,即使是NOI最簡單的題,也是有一定難度的,所以我稱之為中等題。
回家以后要多練這種,有一定難度,有思維要求,並且綜合了多種算法的OI題。它們可能在平時nfls六校聯考的模擬賽中,可能在LOJ里的各種真題中,可能在CF的div1 D,E,F里...。要勇於把它們啃下來,才能進一步提高實力。