# 競賽策略與鍛煉方向 :::info 競賽考驗如何活用有限的資源(時間、腦力等)來取得最大的效益。 ::: 除了知識與實作能力以外,策略以及心理狀態等各方面因素,也會大大地影響競賽的結果,其重要性不可忽視。 要在競賽取得好成績,必須連這些細節也要斤斤計較。 :::info 平常的練習是為了競賽能有更好的成績。 ::: 練習不像打怪練功,只要升級就一定變強。AC 越多題不見得能提升越多實力,因此不能只考慮練習時間以及完成的題數,必須重視從練習中能夠學到什麼、累積到什麼。 本篇以這兩點為大原則,來說明平時練習如何準備,以及賽中該怎麼應對。 ## 閱讀所有題目 閱讀所有題目非常重要。不要急著開始寫第一題,並且絕對不要因為一題不會寫,就不往後看其它題目。 一般競賽會分成兩種:題目按難易度由簡而難排序,或者不按難易度排序。不管哪一種,這個原則都通用。 理由很簡單: :::info 每個人對同一道題目的難度感受不一樣。 ::: 以 APCS 為例,客觀難度是 $1<2<3<4$,第 $1$ 題最簡單,第 $2$ 題實作困難但不用考慮計算效率,第 $3$、$4$ 題則必須想出足夠有效率的解法,但實作相對不困難。 對於實作強,但缺乏計算效率的概念、或想法與知識不足的人,第 $2$ 題不難,第 $3$、$4$ 則很難取得高分; 對於想法強,但實作不夠安定的人,第 $3$、$4$ 題可以很快想到怎麼做並寫出正確程式碼,第 $2$ 題反而會寫起來非常卡。 甚至極端而言,想法強的人每題思考時間差不多都接近是 $0$,那麼實作相對花時間的第 $2$ 題,反而會佔用最多時間,且最難保證正確無誤。 同理,假如有一題較簡單的實作題、一題較難的數學題,對於數學很強但實作不熟練的人而言,反而普遍認為較難的數學題反而更好解決。 ### 配題策略 考慮以下問題: :::success 給你正整數 $N$ 代表賽中有多少題目,接下來 $N$ 個正整數代表每題所需時間,最後給你正整數 $M$ 代表比賽中有多少時間。求賽中最多可解出多少題? ::: 這個問題的答案非常直覺,同時也是競賽的核心策略: :::info 每次從未解出的題目中,找出所需時間最短者來解,直到時間不夠為止。 ::: 為此,你必須知道 - 每一題在問什麼 - 有能力從題目條件與所求,來估算 AC 所需時間 因此,必須先完整閱讀所有題目,才有得配題。 ### 簡單、有把握的先做 :::info 簡單、有把握的定義:$10$ 分鐘內可以 AC ::: 如果存在這等級的題目,可以先做。不過在解題時間不存在罰分時,也可以看完所有題目再做。 不在這等級的題目,或者沒有足夠的把握,就算是確定會寫的,也應該先閱讀其它題目。 另外,即使你有把握,也可能只是題目看錯或估計錯誤,寫的時候必須計時,只要超出 $15$ 分鐘沒有 AC,就馬上先去看別題,之後再回頭想。 ### 子任務是關鍵 :::info 能在 $10$ 分鐘內拿下的部份分,可以嘗試先拿 ::: 理想上,存在部份分的比賽,不應該有任何一題 $0$ 分。能夠拿下的部份分必須把握住。 通常存在部份分,意味著可以用正確、但效率不足的做法去拿;或者進行特定限制時,會變成較單純的題目,有較針對性的解法。 :::warning 品質高的題目,子任務會具備一定的引導性,可能幫助尋找通往正解的方向。 即使目標放在完整解出該題,子任務所含之線索仍然非常重要。 ::: ## 閱讀題目的細節 :::info 若沒有正確理解題意,實力再強也 AC 不了。 ::: 仔細、耐心地閱讀題目,注意每個條件以及數字範圍。這件事非常重要且基本,但重要性卻常被忽視。 有些重要的限制條件,會讓看似困難的問題變得相當容易。因此完整地閱讀非常重要。 有些題目被包裝得看似複雜難解,本質上只是簡單題。 儘管大半的問題,只看最後一段就能知道想問什麼,甚至存在靠範例測資來通靈題目所求的流派,不過不建議用這樣的方式練習。 :::danger 請不要只看範例測資逆推,也不要只看題敘最後一段。 ::: 理由是有些題目重要條件會藏在題敘中,或者用較文章式的敘述來描寫。 特別是練習時,若認為閱讀煩躁而一昧貪快,長久下來會更沒耐心細讀文字、且訓練不到閱讀理解的能力,對成長不見得是好事。 ## 練習估計解題所需時間 理想上,閱讀完一道題目,必須要在沒有其它提示的情形下,在最多 $1$ 分鐘內粗略估算 AC 所需時間。 這仰賴於反覆的估算、計時、並且修正,才能趨於準確。儘管不可能百分百精準,但越準就越有參考價值。 在沒有情報的狀況下隨機選題,不去看 AC 率、難易指標、TAG 或題型等提示,閱讀完題目後,先進行估算,之後計時,AC 後進行比對,並回顧過程思考為何偏離,作為日後估計的參考。 講義的題單適合用來練習單一主題,但不適合拿來練習題型判斷與難易估計的部份;隨機選題在所學不多時容易踩到沒學過的東西或太難的題目,練習效益相對低,可是適合練習判斷力。 :::warning 有前提情報時,對思考部份的估計較不準確,但依然可以用於估計規劃與實作部份所需時間。 ::: 計時和回顧也能協助了解解題過程中,每一步所花時間,以供檢討改進使用。 ### 模擬賽的實際演練 :::info 打模擬賽非常重要。 ::: 實際去打模擬賽,會更了解賽中所面對的情況,包括時間限制所帶來的壓力,以及資源有限時的調度困難。 請避免拿正式的重要比賽作為人生初次參賽來累積經驗,畢竟機會有限,事前能累積就盡量累積,會更有利。 AtCoder 和 CodeForces 都有提供模擬參與過往比賽的功能,vjudge.net 可在支援的 OJ 中任選題目、自由設定時限等來舉辦模擬賽。即使系統不支援,也能自行計時並參考上傳記錄做到類似的事。 ## 卡題時該做什麼 :::info 原則上,一道題目 $5$ 分鐘沒有任何進展,或 $15$ 分鐘看似有進展但沒多大變化,就該先停下來了。 ::: 嚴禁在同一題上連續卡住太久。 人在思考時,特別是不順遂時,容易鑽進死胡同打轉無法脫身,一兩題陷進泥沼可能比賽就這麼結束了。 要換別題,心理上又覺得已經花很多時間了,不捨得放棄或不甘心不肯認輸。 請努力克服。這些都是陷阱,容易成為敗因。 很多時候,先跳脫當前思考,想想別道題目再回頭,會有奇效。 ### 勇於暴搜和暴力 不要因為測資範圍大就退縮,暴搜和暴力雖然算得慢,但能正確算出答案。 就算拿部份分也好,大部份對但少數情況會錯的假解衝衝看也好。 若賽制有子任務,應盡量爭取部份分數。 ### 騙分導論 [騙分導論](https://www.google.com.tw/search?q=騙分導論) 不得不說這很創意,也很實用。雖不建議只學些較邪門外道的做法,紮實的基本功更加重要;但許多時候不擇手段也要爭取分數的姿態是正面且有益的。 ## 訓練時的心態 練習的最終目的是最終在競賽等狀況,需要用到平時累積的熟練與經驗的關鍵時刻,能夠有較良好的表現。 這並非學得更多、寫過更多題目就一定比較好,平常的小習慣也會影響長期累積的成果。 ### 不要過於在意題數 :::info 題數與實力並不相等。 ::: 題數以及(OJ上的)排名雖能提供成就感與動力,同時追求題數也可能帶來不利的影響。例如傾向多寫熟練所以省時的題目、而不傾向寫不熟所以費時的題目,反而阻礙成長。 題數(或者作業)要灌水蒙混過去的方法多得是,不過這樣只是浪費時間而沒有獲得成長。 ### 寫題單時要有目的性 :::info 練習題(或自己找來的特定題型題單)就算有多種解法,應盡量使用目的的方法去解。 ::: 例如放在練習整數與 if 的題目,雖然可能用字串更好解決,但就沒練習到主要想練習的東西。 多想不同解法絕對是好事,但因此沒練習到需要練的東西、或沒想到怎麼用這主題教的東西去解,那其實是一種浪費。 ### 多花時間養成思考習慣 :::info 賽中能少想的事就該少想;練習時應多思考,不要想抄捷徑。 ::: 實作好好摸熟、想通每個細節,不要貪快或瞎猜。寫錯時要去弄懂原因和細節。 自己思考解法至少約 $15$ 分以上,不要太早問人或看解答。 保持不滿於當前做法。隨時回顧解題過程,檢討並思考如何改進。 不盲目地反覆練習。很多時候與其相信熟能生巧,不如從做法的根本去改進、尋找更好的解決方法。 找出一套屬於自己的思考與驗證方法。 :::warning 為了能偷懶而多思考,但不因偷懶而減少思考。 ::: ### 多嘗試不同的做法 :::info 賽中盡量用最熟悉有把握的方式;練習盡量多用不熟悉的做法,或同一題嘗試不同做法。 ::: 熟練的做法最不易出錯,但練習時一直傾向用熟悉的做法,會導致熟悉的東西不夠多、不夠廣。若賽中遇上熟悉的方式行不通、或不那麼適當時,應對能力會不足。 同一題多用不同方式多 AC 幾次,看似題數沒有增加,不過會累積不同的經驗。 ### 試著找出更快的做法 :::info 賽中應在合理計算量(複雜度)中,選擇實作較安定的做法;練習應多想是否存在更快、更簡潔的做法。 ::: 例如今天有方法 $A$ 和方法 $B$,方法 $A$ 明顯比較慢,可是比較好寫;方法 $B$ 明顯比較快,但比較難寫。 一般會認為方法 $B$ 更好,因為它能面對題目更嚴苛的測試資料大小和更緊的時限。 但是若這題方法 $A$ 足以獲得 AC,那麼賽中方法 $A$ 能用更少的資源獲得更多的效益,是比方法 $B$ 更優的選擇。 練習時則應嘗試掌握方法 $B$ 或甚至思考是否存在更快的其它方法,以應對更嚴苛的條件以及測資。一昧貪快選擇方法 $A$ 可以較快獲得 AC 使題數增加,但賽中不幸遇到方法 $A$ 不夠快的情況,就會陷入不利。 ### 從錯誤中學習 :::info 向失敗學習,記取教訓並檢討如何避免失敗。 ::: 面對失敗,不要逃避或者無視。失敗能教給我們的東西,遠比成功多得太多。 不要白白的失敗卻沒得到任何成長,那是種浪費。記住那份痛楚與不甘,並轉成動力。 練習時多失敗是好事,總比重大競賽中失敗得好;只是有時摔不夠重,就學不乖。重大競賽中的失敗,對整體人生或許反而是件好事。 ### 多看官方標準或其他人的做法 :::info 盡量避免在練習前看解答,或至少別太快放棄;AC 後則應多看別人的做法,或可以拿去問人是否有更好的做法。 ::: 特別是像 AtCoder 或 CodeForces 等 OJ 每題都有官方標準解答,建議多看,有時會有意外的收獲。 例如:從未想過的做法、特定技巧的奇妙運用方式、不同的切入問題與看待事物的角度、實作上的小技巧…等。 ### 整理程式碼與邏輯 :::info 思考解法時細分不同狀況想清楚,規劃實作時嘗試整理邏輯,尋找或製造共通性、減少例外。 ::: 例如考慮正整數 $N$ 是否為特定正整數 $k$ 的倍數的情況,很直覺可能會想到若 $N<k$ 那肯定不成立,因此可將狀況區分成單純的 $N<k$ 和較複雜的 $N\ge k$ 兩邊。 最後找到的判斷方式可能是判斷 $N\%k = 0$,再多想一下會發現其實 $N<k$ 的話 $N\%k\ne0$ 必定成立,所以用這個條件判斷時,根本沒必要區分 $N$ 是否比 $k$ 更小。 發想階段區分不同情形是會有幫助的,因此這個思考過程並沒有問題。 有意識的去整理結論,可能得到更漂亮的結果,將來用到相似結論時較有利,習慣整理結論也對思考能力有幫助。 ### 要傳就要一次過 :::info 帶著「每題只有一次上傳機會」的覺悟去練習。 ::: 不應該將確保自己程式碼正確性的責任甩給 OJ。 該負責確保正確無誤的是作者,為此除了範例應自行追測各種可疑或不確定的狀況,待有信心自己能想到的狀況都能正確處理,才上傳做最後確認。 :::danger 千萬不要抱持「雖然不知道對不對,總之先傳再說」「反正傳了就知道」的想法去練習。 ::: 這樣寫程式時很容易粗心、寫錯而沒有自覺,寫程式的習慣容易變糟。 對於後測(賽中無法得知最終結果)或存在罰分(上傳沒有 AC 會受到些許懲罰)的賽制會有相當大的負面影響。 ### 不要逃避實作複雜繁瑣的題目 某程度上,夠麻煩且繁瑣的實作題,更能幫助訓練如何整理程式邏輯、寫出更簡潔且漂亮的程式碼。 或許練習這類題目,單論對競賽的效益並不高。不過對整體程式能力是不壞的訓練。 ### 隨機尋找題目 :::info 嘗試在「不知道題目任何資訊」的情況解題,訓練判斷能力。 ::: 這裡的資訊包括題目粗略的難易度、AC 率與 AC 人數、TAG、題型、提示或其它情報。 這適合在至少把二章學完後、最好三章學完後再開始,才比較有面對大多數題目的基本知識。 隨著知識增加,能運用的技能增加,要在適當的場合找到適當的方法來運用,會因選項大量增加而相對變得困難。 思考無任何情報的未知問題,對於如何尋找解題方向、題目線索的判讀、難易度的判斷、所需時間的估計等,各方面都會有所成長。 如果只寫已知是特定主題的練習用題單,以上的判斷能力會相對低落。 ## 放鬆和休息十分重要 :::info 賽前盡可能放鬆心情、獲得充分的休息,同時注意身體健康狀況。 ::: 休息不足或生病會導致失常,因此不建議賽前因不安而過度的特訓。練習是平常就該練的,賽前臨時抱佛腳意義不大,不如好好休息放鬆。 調整身心狀況在最佳狀態去面對競賽,是一件非常重要、卻意外的容易被忽視的事。 ## 小結 練習以獲取經驗、教訓、各種熟練度為主,為了賽中取得多一點的有利,該花的時間心力不能省。 賽中需活用有限的資源來取得最大效益,透過模擬賽與賽後檢討能更明白賽中需要什麼、如何準備。 以此為基準,真摯地面對每個課題,在平時做好準備、賽前注意照顧身心健康。 {%hackmd @sa072686/__style %} ###### tags: `競程:初章後半`, `競程`