ACRush 樓天成回憶錄

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧。首先是 GCJ2006 的回憶。

Google Code Jam 2006

一波三折:

Google Code Jam 2006 是我第一次到美國參加現場的程序設計比賽。 Google Code Jam 2006 的比賽地點設在了紐約,這次紐約之行之前的簽證出了不小的問題,這裏非常感謝大家對我們的關心,特別感謝吳總( wyy )和魯小石的幫助,使我最終踏上紐約之旅。

從北京到紐約的飛行時間是 13 個半小時,由於是第一次做超過 8 小時的飛機,沒有什麼必要的經驗和準備,路途非常疲勞。一到賓館就睡了,結果由於手機鈴聲的時間使用的是東方時間,差了 12 個小時,一覺把所有事情連晚飯一起都睡過了,隨便吃點東西就繼續睡了。之後的所有現場比賽我都養成了提前睡覺的習慣,以保證充足的體力。

比賽過程:

比賽時精神狀態還算可以,但是分配了比賽房間之後發現自己和 tomek 分在一個房間,真是很不爽;在和旁邊的 zhuzeyuan 抱怨的時候,發現他和 Petr 一個房間,彼此彼此吧。

下面就是比賽過程了,總體來說比賽過程比想象的艱苦,不過其實在 System Test 之前的結果還是很滿意的,先簡單描述一下 3 道題目吧。

250 分的題目是一道平面極值問題,給定 n 個點,求一條直線,使得 n 個點到這條直線的 y 方向截距總和最小。我回憶起金凱在 2003 年集訓隊論文中報告中講到的很類似的一道題目,記得一個重要結論是這條直線一定經過兩個點,雖然題目有些不同,但是很快得到了相同的重要性質:這條直線一定經過兩個點。這樣很容易得到一個 O(n3) 的算法。

500 分的題目是一道反 Hash 函數問題,給定一個 Hash 函數和 x ,求一個最小的非負數 y 使得 H[[yes]]=x 。估計了一下,單向搜索需要 26^8 ,於是我改用雙向搜索,這樣就變成了 26^4 。但是實現過程比想象的複雜很多,提交了後只有 280 左右了。其實,這題有更簡單的數學方法, tomek 的程序有 450+ 。

1000 分的題目是涉及卷積函數和計算反函數的問題,通過轉化變成線性方程求解問題。當時受到現場氣氛的影響有些緊張,浪費了不少時間,提交之後 550 分左右。其實,當時一些原理問題都沒有想清楚,不過後來和 Ying (王穎)經過討論驗證都是正確的。

Coding 結束之前 Petr , tomek , Ying 和 andrewzta 都提交了 3 題,其中 Petr 領先得比較多,我和其餘 3 人差距 50 分以內。

Challenge 階段開始之後,我由於 500 分題自己使用的是雙向搜索的算法,沒有注意到有些單向的搜索加模線性方程的方法其實是正確,在 10 分鐘以內 cha 錯了 2 次。落後於上述的 4 個人,排在第五。

但是下面的 5 分鐘發生了戲劇性的一幕,首先是 Petr 的 250 被 cha 了,接着 Ying 的 250 也被 cha 了,這樣我面臨這樣一個情況: tomek 領先我 100+ 分, andrewzta 領先我 30+ 分,由於我和 tomek 處在一個房間,所以我做出了一個大膽的決定,就是 challenge tomek 的 1000 分題,我隨機生成了一個隨機大數據,在最後時刻提交了這個 challenge ,系統返回了一個令人窒息的結果: successfully challenge 。憑藉這 50 分我一舉超過了 tomek 和 andrewzta ,在 System Test 之前佔據了榜首的位置。

戲劇性的結果:

我很有幸能夠在第一次參加現場比賽時,就能夠和冠軍這麼接近,如果 System Test 能夠全部 Pass 的話,這可以認爲是一場完美的比賽。

可是,整個故事就好像是被刻意設計的一樣, System Test 之後的結果使我目瞪口呆:首先是 250 分的題目,我由於有一個地方沒有及時使用 double ,而造成整數越界;然後, 1000 分的題目簡直是悲劇的最高境界,我在高斯消元的時候沒有及時把一個重要變量暫存,導致影響了結果,沒有想到竟然躲過了那麼多大數據,但是不能通過 System Test 。最後排在 50 名左右。這兩個錯誤至今刻骨銘心。

最終 Petr 獲得冠軍, Ying 亞軍, andrewzta 由於 500 掛了排在第 3 。

11 月的紐約有些冷,我隨大隊人馬一同去了一趟帝國大廈,景色很迷人。第二天休息一下後與幾個中國選手打了一會 “ 找朋友 ” ,第一次美國之行就結束了。

總結:

比賽結果雖然不是很理想,但是對於第一次參加世界比賽的我還算可以接受。也算是爲今後的比賽留下一些教訓吧。

在帝國大廈上見識了大家的拍攝功底,我由於技術差沒有拍到任何合適的照片。

在比賽過程中,首次見識了 liympanda 的大將風度,和 panda 在一起總是笑口常開,他無論遇到什麼情況都無所畏懼,這一點我一直在努力學習,不過一直做的不好。但是 panda 打牌的時候就不一樣了,總是喜歡偷看別人的牌,還炫耀自己會說廣東話,被 Ying 和 rocking 兩位廣東選手狠狠鄙視了一番。

Petr 加上之前的 TCO 和之後的 TCCC ,拿到了 2006 年的大滿貫,可以算是歷史性的突破吧。 Tomek 有些可惜,比完了還問我怎麼 cha 他 1000 分的,呵呵。

其實這次比賽 Ying 挺可惜的,其實 Petr 的發揮並不很好,如果 Ying 運氣再好一些的話,歷史從那時就要重寫了。不過 Ying 還是體現了他超強的數學功底,讓人佩服。另外,來自復旦的同省隊友 LemonTree 也獲得了好成績。

這好像是自己最後一次和 xreborner 同場競技了(由於之後 xreborner 退役了很長時間,忘記 GCJ2008 我們又見面了,謝謝 Savior 的提醒),感謝您在我高中時期教授了我許多編程技巧,我一直沿用至今。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧。昨天是 GCJ2006 的回憶,今天時間上更早一些吧,我現在還清晰記得 3 年前,我剛剛參加 ACM 時參加北京賽區 2005 和杭州賽區 2005 的情況。

2005 年 ACM-ICPC —— 酸甜苦辣

我進入清華大學開始本科學習的時間是 2004 年 8 月,在進入清華大學的第一年裏,由於基礎課學習比較緊張,再加上計算機系不允許大一學生自帶電腦,我沒有參加 2004 年的 ACM 比賽。不過在大一一年中沒有停止這方面的練習,對 ACM 還是熱情高漲。

大概在 2005 年 7 月底,與同班同學 shell (貝小輝)和 superzn (張寧)一起決定組隊參加 ACM 比賽。對於隊名沒有太多的想法,就隨便取了一個字典序靠前一點的 bomber 。隨後進行的幾場訓練中,我的編程狀態一直保持得很好,訓練比賽的主要方式都是:我主寫程序, shell 和 superzn 負責翻譯題目,思考算法和測試。這種組隊模式一直沿用到我們後面的所有比賽中。

2005 年底,我們報名參加了 2005 年的北京賽區和杭州賽區的比賽。順利通過了預賽進入了現場決賽。記得當時北京賽區預賽的時候,我和 superzn 一起在參加百度之星程序設計大賽, shell 依靠一人之力過了 6 題,最後以第二名的資格參加北京賽區現場比賽。

北京賽區:

2005 年的北京賽區地點設在隔壁的北京大學,由於交通非常方便,我們沒有和大部分選手住在一起,不過也沒有參加 Java-Challenge 和晚上的表演。

練習賽之前,說到比賽位置抽籤,本身意義不是很大,可是鄔老師神奇的 RP 把兩隻清華的隊伍抽在一起,結果練習賽進行了一半,另一隻清華的隊伍 THU1 (隊員是:吳景嶽,慄師和金凱,好像後來隊名改成了 DreamCatcher ,不是很確定)被要求換到一個比較遠的地方,理由是有些學校覺得這樣不合理。後來很多賽區也出現過隊伍座位在一起的情況,鄔老師的 RP 果然不是蓋的。

記得練習賽時和復旦的 LemonTree (盛城)一起在場地裏閒逛,結果果然不到 10 分鐘就被要求回座位了。還有當時比賽場地是一個體育館,有些隊伍把氣球放飛之後氣球就飄在天花板下了,總裁判李文新老師還威脅我們說,如果明天正式比賽把氣球放飛,就不算通過相應的題目,除非有辦法把氣球取下來。

然後就是比賽的過程了,下面有底紋的文字是我找到的當時留下的比賽總結:

E :快速排序。 5 分鐘 1Y 。

我想 5 分鐘的時間可以爭取這幾年 ACM 國內賽區的最快出題記錄了吧。

G :二分答案 + 最小生成樹。 25 分鐘 1Y 。

這題就是經典的最優比例生成樹問題,我們一致認爲這題比較簡單。不過後來被李文新老師批評了,說法是誤導其他的隊伍。不過說到最優比例生成樹問題, TCO2006 的時候 fwj 和 tomek 竟然都沒有見過這道題目,這題可是源於 POI 呀。我想我們認爲這道題目簡單的主要原因是我們都在冬令營上見過這到題目,如果第一次看見,想出算法可能確實需要一些時間。在這裏向被我們影響的隊伍的道歉,最終 G 提交了 200 多次,但是隻有 8 個隊伍 AC 。

C :二分圖最大匹配。 42 分鐘 1Y

題目要求計算一張圖的最小覆蓋集,可能唯一的 tricky 是發現圖是二分圖。

D :遇到了一定的困難,發現 A 很簡單,於是先放一下

D 是一道比較綜合的題目,設計一些簡單的計算幾何和字符串處理的知識。

A :簡單的幾何問題,出現了一個低級錯誤,提交了 3 次均爲 WA 。

A 是北京賽區最簡單的題目,我的程序裏犯了一個很低級的錯誤,可能也是經驗不足造成的吧。

D :重新寫,但是沒有考慮一種情況, WA 了 1 次。

87 分鐘,復旦的 Abuacus 過了 4 題佔據了 Rank1 。由於隊伍模式的原因,我們在還有很多簡單題目的情況下卡住了長達 30 分鐘。

A : shell 突然發現了 A 程序中的低級錯誤, 105 分鐘 AC ,重新奪回 Rank1 。

這是很重要的一步,現在想來如果沒有這個發現,後果可能不堪設想。

B :二分答案 +2SAT 。 129 分鐘 AC 。

B 是一道明顯的 2SAT 問題,由於題目比較長,我們沒有很早發現這道簡單題。

D :發現了 D 的沒有考慮的情況, 140 分鐘 AC 。

看了一個 board ,那時 Abuacus , Eccentric 都只有 4 題,能夠在第一次參加正式比賽就做到 6-4 的領先,當時心情很激動,不過由於缺少經驗,也影響了接下來的發揮。其實,現在回想起來,這次比賽其實是一個很好的 AK 的機會。

F : DP 。程序比較複雜, WA 了 4 次。

F 是一道比較複雜的動態規劃的題目,其實 WA 的原因是一個應該用 int64 的地方,我們使用了 int ,這個地方的確很難發現。

H : F 一時無法 AC ,只好轉功 H 。 H 就是普通的模擬題。開始沒有考慮坦克和炮彈可能在 1/3 秒相遇, WA 了 1 次。

比賽還有一個小時,封板。

H : shell 發現了坦克和炮彈可能在 1/3 秒相遇的情況, 250 分鐘左右 AC 。

對於我們這種組隊模式,當主寫程序的選手狀態不好的時候,很容易出現連續卡題的情況,這種情況的出現很不利於水平的正常發揮。在北京賽區的比賽中,我們很有幸沒有出現連續卡處的情況。

記得,當時北京賽區的 Judge 的半自動的,就是說如果結果是 AC ,速度就會非常快,否則由於人的介入,不能 AC 的提交往往需要等一段時間。我們第 2 次提交 H 之後,沒有得到很快的回覆,以爲已經 WA 了,於是我和 superzn 繼續測試一些數據。但此時,突然有一個 mm 從左邊走過來插氣球,這個氣球也成爲了全場唯一的藍色氣球,這個意外之喜最後成就了第一個分區賽冠軍。

F :下面就是痛苦地提交 F ,一直戰鬥到最後一刻, WA 了 14 次,留下了北京賽區最大的遺憾。

在最後時刻我們似乎發現了那個 int64 的錯誤,不過當時思路已經比較混亂了,沒能改對。 F 的問題也導致沒有時間寫 I ,當時如果直接重寫後者換 superzn 來寫 F ,完全可以在比賽結束前 AC 。

比賽的大致過程如上所述,那個神奇的氣球,我現在仍然記憶猶新。最終有 4 個隊伍攻破 7 題, Abacus 的組成應該是盛城, timegreen 和 suzhan 吧, Eccentric 中我只記得辛韜, ZSU_Panku 中我記得 Savior (陳實)。上述的老朋友之後見面的機會就很少了,分區比賽也成爲了我好需要老同學重要的交流機會了。

我 ACRush 的 ID 估計就是那時開始使用的吧,轉眼就已經 3 年多了。

比賽前後還記得經常與復旦大學的吳永輝老師聊天,在那之後的每次比賽我都能見到他年輕的身影。

現在回想起北京的分區賽,很有幸能夠在第一次參加 ACM 正式比賽就獲得分區比賽的冠軍。我想是由於現場氣氛對許多隊伍都有不小的影響吧,當時許多隊伍都卡在幾道比較繁瑣的題目上了,題目的算法性都不是很強。我大概從那時纔剛剛接觸 TopCoder ,如果能夠早一些,相信會更適應這樣的比賽。

杭州賽區:

2005 年的 ACM 杭州賽區比賽在浙江大學舉行,杭州賽區的時間就在北京賽區結束後一週,最初選擇杭州賽區的原因很飄逸:我自己家在杭州。實際上也差不多,我隨隊伍(當時 THU 派了 3 只隊伍參加杭州賽區的比賽,除了我們隊之外, b142857 (侯啓明), zhy (周源), ysy (楊思雨)組隊,另外一隻由汪汀,王俊和黃源河組成)一同抵達杭州車站之後就馬上回家休息了,直到比賽前才趕回。在北京到杭州賽區之間的一週中,我的狀態就在不斷下滑,在家中完全失去了比賽的氣氛,回到賽場再也找不到感覺了。一場悲劇即將上演。我們先看看比賽過程吧,下面有底紋的文字是我找到的當時留下的比賽總結:

G :初看很簡單,但是調試了 30 分鐘沒有結果。

G 是一道數學問題,其實《具體數學》書上有明確的公式,不過我們使用的遞推方法應該也可以得到正確的結果。程序中犯了一些低級的錯誤,由於實在不在狀態,調試了 30 分鐘還沒有找到錯誤。這裏還暴露了一個組隊模式的問題,在後來的組隊模式中,如果像這樣沒有想清楚算法的題目隊友是一定不允許我去寫的。

A :模擬。 41 分鐘 AC ,當時肯定沒有想到這是唯一一道 1Y 的題目。

A 是一道模擬題, 1Y 的時候已經很晚了,排名也很靠後。

C :圖論。但是由於堆棧逸出 RTE 了 5 次,浪費了大量的時間。

C 的問題關於樹中祖先關心的判定,題目很簡單,實現的方法也很容易,就是通過一遍 DFS 來計算。但是我們忽視了一個從來沒有遇到過的問題:堆棧溢出。而且,堆棧在本地機器上運行過程中, Eclipse 提供了 8MB 左右的堆棧,所以沒有溢出,但是在提交之後的環境下運行就溢出了。而且每次 RTE 之後,我們一直在嘗試修改數組的大小,一直沒有找到根本原因。調試 C 的同時,我也嘗試修改 G ,結果 G 也錯了 8 次之多,並且始終都是 WA 。

I : shell 在我鬱悶地調試 C 和 G 中 AC 了,之前 WA 了一次。

I 是動態規劃問題, WA 一次可能是忽視了一些邊界情況。

D :網絡流,沒有想到先貪心進行優化。 TLE 了 5 次最終沒有通過。

D 就是計算最小割,我們事先準備了先流推進算法,不過根據這道題目的模型,先流推進算法遇到最壞情況:二分圖。由於當時 dinic 還不是很流行,我們 TLE 了 5 次還沒有通過。

鬱悶地調試 D 和 G 。

E,B :都嘗試過,但是都出現了不明的問題。

在隨後的時間裏,不斷調試 D 和 G ,但是始終不能 AC 。之後又嘗試 E 和 B , E 通過分段的方法可以處理, B 是數學題目。正常的話 E 和 B 並不是很困難的題目,但是當時已經非常混亂,連樣例都沒有通過。

最終我們只過了 3 題,排在 21 名,經歷了我參加 ACM 以來最慘痛的失敗。這次失敗主要歸過與我狀態太差,基本上什麼題目都不能順利通過。當然題目的選擇也有很大的問題: G 確實不是難題,但是由於未知的原因始終不能通過,後來我把紙上的程序敲在 ZJU 上就 AC 了,至於現場爲什麼不能 AC 我現在還是不能明白。如果說第一題的選擇直接影響了我們的信心,那麼 D 的堆棧溢出則完全打亂了我們的節奏。對於我們的組隊模式,卡出 2 題已經超出了極限,我們不可能再嘗試其他題目。

Abacus 也來到了杭州,他們前期體現了強勁的先期優勢,在 2 小時就達到了 6 題; b142857 (侯啓明), zhy (周源), ysy (楊思雨)的隊伍表現得相當神勇,在最後一小時超越了 Abacus ,奪得了冠軍。

杭州賽區的失敗至今仍是心中痛苦的回憶,不過這個教訓也是對我今後的學習生活的一種警示。

總結:

2005 年是我第一年參加 ACM-ICPC 的比賽,兩場 ACM 分區賽,我們經歷了奪冠的興奮,也經歷了環顧四周等待比賽結束的無奈。 2004 年清華沒有獲得任何分區賽的冠軍, 2005 年清華打了個漂亮的翻身仗,先後在成都,北京和杭州奪得冠軍,而且是三支不同的隊伍。

兩個賽區的 G 都是有傳奇色彩的題目。北京賽區中,我們 25 分鐘 1Y 了 G ,導致許多隊伍跟風失敗,最終達到了 208 提交 8AC 的低通過率。但是,杭州賽區中, G 從比賽一開始就佔用了我們大量的時間,直到最後都沒有通過,估計至少浪費了兩個小時左右。真所謂成也在 G ,敗也在 G 。

北京賽區後, POJ 的論壇上傳聞說我曾經說過 “ 起身去廁所,不許碰鍵盤。。。 ” ,很敬仰那些同學搞笑和扯淡的功底,我們雖然定下了以我主寫程序的組隊模式,但是也非常重視配合和每個人在隊伍中的重要作用。

當時清華沒有組織校內 PK 選拔,選擇了成都賽區的冠軍隊 THU1 參加全球總決賽,當時總決賽隊伍是以參考第二賽區的成績決定的,現在回想起來也是很合理的。由於最終我們未能得到機會參加全球總決賽,接下來幾個月我們情緒低落, bomber 從那時也就宣佈解散了吧。

2005 年的比賽過程中,我見到了許許多多的老朋友。用吳永輝老師的話, ACM 競賽可以看作一些老朋友一起進行的一場智力遊戲。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧。回顧了 GCJ2006 和 2005 年的 ACM 之後,轉向 TopCoder 的比賽吧。我參加的最早的 TopCoder 賽事是 TCCC2006 。

TCCC2006 —— 死亡之組

TopCoder Collegiate Challenge( 簡稱 TCCC) 是 TopCoder 一般在秋季舉行的面向全世界在校學生的程序設計大賽, 2006 年的 TCCC 在聖地亞哥舉行。從北京到舊金山的飛行只需要 11 個小時左右,所以不至於那麼疲勞。路上一切都很順利,很感謝 OpenGL 的提醒,對於超過 8 個小時飛行自帶拖鞋和枕頭對我來說還是很重要的。

TCCC2006 使用的標準的 TopCoder 現場比賽形式,比賽有 48 名選手參加,首先 48 名選手被分爲 16 個人一組,每組分別進行半決賽,前 2 名直接晉級決賽, 3-6 名晉級 wildcard 比賽, wildcard 比賽 12 人中的前兩名填補決賽的最後 2 個名額,決賽由 8 個選手參加。 TopCoder 現場比賽中很重要的一個創新是:每名比賽選手在觀衆席前都有一個同步的顯示器,這樣觀衆可以看到選手任何時刻做的事情,極大增強了互動性。

TCCC2006 的 Room 1 和後面的 Final Round 都可謂是死亡之組。現在就回憶一下這兩場激烈的比賽吧。

Room 1 :

至於 3 個房間的分配, TopCoder 按照註冊截止時選手的 Rating 分佈蛇形分配。但是 TCCC2006 的房間實力分佈極不平衡,我與上屆冠軍 tomek ,著名選手 reid , Egor , halyavin 還有 Rating 不高但是實力極強的 Ying 和 ardiankp 同被分到了 Room 1 ,賽前 Room 1 成爲公認的死亡之組。

在聖地亞哥,我和師兄 Macsy (張一飛)同一個房間,很感謝師兄的關心,我那幾天休息的都很好。要知道如果同房的人有 10 小時左右的時差的話,一人必須很小心才能保證不影響另一人的休息。

Room 1 在我抵達美國的第二天早上進行,選手允許提前 30 分鐘準備一些必要代碼。不過現在大家都比較喜歡學習 Petr 那樣一行代碼都不打。下面就是比賽的過程:

250 分題目是:給定 n(n<=50) 個整數 AI 和一個閾值 d ,計算 n 個整數所有排列 PI 中滿足 |API-API+1|<=d 的排列中,所有不同可能 AP1 的個數。這題最標準的方法是動態規劃,基本思想是把 n 個整數排序之後,計算兩條相鄰元素不超過 d 的序列。我使用了一種更精巧的算法,把 n 個整數排序之後,對於 AI ,如果 AI 可能作爲排列的第一個元素,那麼 AI 必定在某一個方向(大小)連續而在另一個方向每間隔兩個元素相連。這個算法比較容易實現,但是正確性證明比較難,甚至讓人第一感覺是錯的。我寫完程序測試了所有樣例都正確就提交了, 243 分。提交之後我又測試了許多數據,並在紙上嘗試證明正確性。

賽後,我看了網絡上的討論記錄。在我提交 250 分題之後,立刻遭到了 misof 的懷疑,他認爲我的算法有問題。據 Macsy 學長的回憶, OpenGL 在我屏幕前看我寫完程序,也認爲我的算法是錯的,不過後來他們討論之後發現沒有反例。

關掉 250 分題目之後,我剛剛意識到 Room 1 的 3 題分數不是 250-500-1000 ,而是 250-600-900 。現在看來,對於 250 比較順利的情況,應該先做 500 ,若 250 不順利或者想出奇制勝的話,可以先開 1000 分。當時沒有什麼經驗,我認爲 900 比 600 應該簡單一些,於是就打開了 900 。

900 分題目是:給定一張 n(n<=10) 個點的帶權有向完全圖(也就是 n2 個實數)和一個衰減係數 p ,求一條經過 d(d<=10) 條邊路徑(不需要保證簡單路徑),要求這條路徑的指數衰減長度(指數衰減是指第 i 段的長度乘以 pi-1 然後求和)最接近 1000 。這題如果使用窮舉法,就需要 1010 左右的計算量,在 TopCoder 的測試機上也不能通過,由於路徑長度很容易超過 1000 ,所以很難找到多項式時間的動態規劃。我馬上有了一個想法 —— 雙向搜索。對於長度爲 d 的路徑,其實可以看作從某一個點 p 出發的一條反向的長度 [d/2] 的路徑和一條正向的 d-[d/2] 的路徑,對於固定的節點 v 來說,這種兩個方向的路徑都不超過 n[d/2] ,這樣只要枚舉一個方向的路徑然後二分查找另一個方向即可。複雜度是 O(dn2+[d/2]) 。

現場比賽調試環境不是很好,我花了不少時間調試以發現程序中的錯誤。提交之後 690 多分,還不到 700 。不過對於 900 分的題目在那種壓力下還可以接受。提交之後我花了 15 分鐘左右測試,沒有發現錯誤。於是就準備做 600 了。

600 分題目是:一道經典的數學題,給定一些盤子疊放的規則,計算頂層盤子的最大可能大小。其實算法不是很難,只要二分頂層盤子的大小,然後依次貪心計算來判斷底層是否能夠滿足即可。只是貪心的時候要考慮兩種情況,一時想不清楚。我當時已經感覺很疲勞,思路不是很清楚,最後 40 分鐘時間也沒能調試通過。這題過於瑣碎, Room 1 中最終沒有選手通過 600 分題,並且成就了一個刺激的 Challenge 階段。

Coding 階段我和 tomek 採用了截然不同的策略,我跳過 600 直攻 900 ,而 tomek 在 600 中掙扎了很長時間才放棄。 Coding 階段結束時,有 4 名選手提交了 3 題。我依靠速度優勢領先同樣提交 250 和 900 的 tomek 35 分左右。

Challenge 階段開始時,我盲 cha ( blind challenge )了一個最後時刻提交的 900 分程序,但是由於我選擇的數據實在太弱,失去了 25 分。這樣我和後面的 tomek 只相差 10 分左右了,所以我決定只要 tomek 不動,我也不動了。其實,當時 tomek 已經知道自己的 900 是錯的, Challenge 階段他估計已經放棄了。我的 Challenge 階段最終就以 -25 分結束。

之後的 Challenge 就是 Ying (王穎)展現勇氣和智慧的舞臺了。他 Challenge 掉了所有提交的 600 ,憑藉 225 分的加分超過了我,排在榜首。這樣比賽的形式也一目瞭然了, 7 位選手提交了 900 ,我依靠速度優勢領先第四名 reid 超過 100 分。只要我兩道題目能夠 Passed System Test 就足以進入 Final Round 了。

System Test 之前,我和 Ying 討論他 “ 超神 ” 的 Challenge 階段。這是我第一次參加 TopCoder 的現場比賽,發現 System Test 結果顯示是按照 System Test 之前的排名倒序進行的。測試到我時,除了 tomek 的 4 名選手的 900 都過了。顯示我的結果時,兩個綠框閃爍了很久終於顯示出了兩個大大的鉤,我終於可以歡呼慶祝勝利了。我前面的 Ying 也兩題全過了。這樣我們兩位中國選手得以在死亡之組攜手出現,這場比賽真可謂是中國選手的勝利。 Reid 只能在 Wildcard 賽再作努力, tomek 則被直接淘汰出局了。

Final Round :

接下來的兩天裏,我觀看了 Room2 , Room3 和 Wildcard 的比賽。第 2 天晚上我們參加了 TopCoder 贊助的 Laser Tag 遊戲,我們所有中國人組成了一隊,我的發揮很差,原因是這個遊戲與 CS 不同,選手頭上沒有感光器,而我喜歡遇到人就攻擊頭部,所以狹路相逢多半是我失敗。活動中,我有幸結識了許多 Dev 的神人,當時由於 vividmxx 沒有參加, magicpig 和 PE 的競爭很激烈,最終 PE 獲得了 “ 浙江大學建校 100 年來第一個 TCCC 冠軍 ” 。記得賽後我 uncle 來到現場,我 uncle 是浙江大學本科畢業的, magicpig 見我 uncle 第一句話就是 “ 浙江大學建校有 100 年曆史了吧? ” 汗死了。另外 zjq 也獲得了 Design 的亞軍。

第三天中午 Championship Round 開始了。決賽時,場地裏安裝了很多攝像頭,可以說我們的任何舉動都在嚴密監視下了。這回我提前確認了題目分數是標準的 250-500-1000 的分佈。參加決賽的選手除我之外有: andrewzta , ardiankp , bmerry , Eryx , mathijs , Petr 和 Ying 。面對決賽選手的實力,我已經沒有意義定一個類似於 “ 保幾爭幾 ” 的目標了,努力發揮自己的水平是最應該做的。下面就是比賽的過程了:

250 分題目是:給定 n 個正三角形,每個頂點都有數字,選出 6 個三角形拼成一個正六邊形,要求相鄰的數字必須相同。三角形允許旋轉,計算能夠得到多少個本質不同的正六邊形。題目很長,我仔細讀了兩遍纔開始寫,算法很清楚,就是枚舉六邊形中心和四周的 7 個數字,然後判斷是否有足夠的三角形。在判斷本質不同的時候犯了一個錯誤,調試了幾分鐘,提交之後只有 215 分了,看了一下排名, Petr 有 232 分之高,其他選手都還沒有提交。測試了幾分鐘發現程序的運行時間不是很穩健,很容易到達 0.8 秒左右,測試了 15 分鐘之多才逐漸放心下來,因爲基本上所有數據都 0.8 秒左右。賽後 Macsy 告訴我,我的程序速度瓶頸是在 set 的判斷,所以時間比較穩定,不會超時。我當時的猶豫和沒有經驗浪費了至少 20 分鐘的時間。

按照賽前的計劃,我這時應該打開 1000 的題目的,但是由於自己對 250 沒有信心,而且求穩思想比較重,我先打開了 500 分的題目。現在看來,開 500 分的題目並不算錯誤,其實在打開 500 分題目的時候,與 Petr 的差距不是很大。

500 分題目是:給定一個機器人的移動命令序列,要求計算結束時機器人的位置。由於移動序列中允許 () 這樣的重複操作,直接模擬是超時的。這類題目的標準算法是利用矩陣乘法,由於之前對於此類題目沒有經驗,沒有準備好就開始寫了,導致矩陣處理失敗。我果斷放棄了調試,換用一種記錄中間結果的搜索方法,寫完的時候已經只有 280 分了。更重要的是我已經沒有時間進攻 1000 分了。提交之後排在第 3 ,前面是 Petr 和 Eryx 。

1000 分題目是:給出一個排隊取菜的模型,計算一個等待時間的排隊序列。而且對於多種答案的情況,要求計算字典序最小的序列。題目其實不是很複雜,集合動態規劃就可以解決,不過模擬取菜過程時需要非常注意細節。 Petr 提交了一個 660 分左右的程序, Ying 則在最後一分鐘提交了 400+ 分,排在第 2 。

Challenge 階段顯得很枯燥無味,前兩天大發神威的 Ying ( +225 )和 Petr ( +300 )都沒有嘗試 Challenge ,整個 Challenge 階段沒有任何一個 Successful Challenge 。

System Test 結果出來了,在 bmerry , ardiankp 和 andrewzta 都只通過一題的結果出來之後,排在我後面的 mathijs 兩題都 Pass ,隨後我的 250 和 500 也都 Pass 了。但是,排名在我之前的 Eryx 和 Ying 的 500 分和 1000 分都 Failed System Test 了,我瞬間提升到了第二名的位置。不過雖然 Petr 的 1000 分掛了,但是他依舊憑藉 250 和 500 的速度獲得了冠軍。

在這裏說一下 1000 分的真實情況吧,因爲這些時間來對於 TCCC2006 Final Round 的 1000 分題目有很多不同的說法。比賽結果中顯示沒有選手通過 1000 分題,如果仔細分析測試結果, Petr 的程序由於超時出錯,而 Ying 的程序由於一個地方沒有清 0 而導致錯誤,確實很可惜。因爲如果 Ying 的 1000 能夠 Pass 的話,他將是 TCCC 的冠軍。不過 Ying 的算法犯了與造成 Petr 超時一樣的錯誤,他們的動態規劃程序比標準方法多出一個 n 倍的時間,我曾經成功生成了一個用例,可以讓 Ying 和 Petr 的程序都超時,這個例子已經得到了 Ying 的認可。需要指出的是 TCCC2006 是 TopCoder 的測試機的速度還是很慢的,兩個程序如果在現在的機子上運行可能只需要 1 秒左右了。

比賽之後和 uncle 到 downtown 遊玩了一下,參加完頒獎晚會,第二天就回國了。

總結:

TCCC2006 是我第一次參加 TopCoder 的現場比賽,很有幸能夠在這麼多的第一次中就進入決賽並且獲得第 2 名的成績。很感謝同參加比賽的同學 Macsy , OpenGL , Ying 還有 PMH 的關心和幫助,你們在我比賽時全程在場邊,讓我感覺很溫暖。

另外,我還有幸認識了 visualage ,現在他已經是 arena 的負責人了吧。記得他和 OpenGL 在 Room 1 的 Challenge 階段通過大聲叫中文(在國外,這是最好的密碼)告訴我 tomek 的 900 是錯的,可惜我沒有聽見。

TCCC2006 對於中國來說是不小的收穫,中國選手佔領了 Dev 比賽, PE 獲得 “ 浙江大學建校 100 年來第一個 TCCC 冠軍 ” , magicpig 和 zjq 分獲 Dev 和 Design 的亞軍,也就是說中國包攬了所有亞軍。在比賽之餘,我很高興認識了衆多 TopCoder 的朋友。

Petr 在決賽中表現了非常良好的狀態, TCCC 的奪冠標誌着 Petr 收穫了 2006 年的大滿貫。 Ying 也採用了很合理的策略,只可惜他的賭博由於運氣差一些惜敗。我採用了比較保守的策略,在所有決賽選手中排名第 2 ,這也是我在 TopCoder 的現場賽事中的最高名次了。

TCCC2006 我很感謝家人的關心,父母凌晨很早起牀查看我的比賽結果,而 uncle 還特地趕來現場爲我加油。這幾年的 TopCoder 現場比賽的贊助商列表裏都能找到 American Online(AOL) 的身影, TCCC2006 是 AOL 唯一一次進行了 3 個小時左右的全程直播,父母和 uncle 都在網絡上觀看了現場的影像直播。

TCCC2006 我神奇地保持了 100% 的正確率,我個人認爲 TopCoder 現場比賽對正確率提出了更高的要求,我們不必太在意 Coding 階段的那些高分,只要自己的程序是正確的,就是成功的。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧。回顧 GCJ2006 , ACM2005 , TCCC2006 和 ACM2006 之後,今天簡要回顧一下國內個人賽場吧。

國內個人賽場 —— 百度之星

國內個人賽場中最重要的比賽要數每年一度的百度程序設計大賽,到今年爲止已經舉辦了 4 屆,每一屆我都全身心地參加了比賽的全過程,百度程序設計大賽是中國舉辦的規模最大的公開程序設計比賽,其參加人數比許多世界範圍的程序設計大賽的人數還要多得多。另外在 2006 年初, Google Beijing 舉行了 Google Code Jam China 的比賽,剛剛開始參加 TopCoder 的我也加入了這次 GCJC 之旅。

第一屆 baidu 程序設計大賽:

最早的國內個人程序設計比賽要回憶到 2005 年 9 月開始的第一屆百度程序設計大賽了,源於宿舍走廊中的海報,我以嘗試的心態報名參加了第一屆百度程序設計大賽。每一屆百度程序設計大賽都由初賽,複賽和現場決賽組成。

第一屆百度程序設計大賽中,印象最深的複賽題目就是那道規模巨大的最小樹形圖問題了, 100000 的數據規模嚇退了不少選手,我鼓足勇氣提交了一個理論上能夠運行的程序,順利通過了複賽進入決賽。最小樹形圖算法在大多圖論書上就接在最小生成樹算法後面,但是其程序量遠比最小生成樹大,而且用途沒有最小生成樹廣泛,在大多數競賽中很少出現。我最早接觸最小樹形圖算法是在 2003 年 4 月,當時正在復旦大學訓練,記得關於這個問題和 xreborner 討論了很長時間才得以證明算法的正確性並實現出高效的程序。

現場決賽於 2005 年 10 月底在北京舉行,由於當年比賽的知名度不高,時間上還和 GCJ 衝突,沒有太多的頂尖高手參加。清華大學除我之外只有 superzn (張寧,我們留 shell 一個人參加 ACM 北京賽區預賽 L ),當時 OpenGL 還是以高中生身份參加的,還有復旦大學的 xreborner 和 young (李陽);中山大學的 magicpig , Savior 和張子臻(不好意思,我不記得您的 ID 了,好像杭州 2008 的時候我們還說起此事)。我一直認爲,現場比賽過程的一個重要的意義在於提供了一個老朋友重逢和結實新朋友的機會,選手之間的交流是比賽中最重要的組成部分之一,我很有幸能夠在這些比賽中認識了衆多牛人。

稍微回顧一下決賽的題目吧:決賽的題目是經典的 8 數碼問題,給定初始狀態和結束狀態,計算最短需要的轉移步數。對於分數相同的情況,按照程序的運行速度排名。比較容易想到的方法有:

(1) 單向 BFS :最壞情況需要 1s 左右。

(2) 雙向 BFS :如果先判斷無解情況,這是 xreborner 使用的方法,平均情況大概 0.002 秒左右。

(3) A* 或者 IDA* :先判斷無解情況,然後通過距離啓發函數搜索。平均情況大概 0.002 秒左右。我當時使用了 A* 的方法,但許多地方的實現不是很合理。

(4) 常量表,這是最有挑戰的方法,因爲決賽的提交量限制在 64K 以內。

現場比賽中, (2) 和 (3) 的使用人數比較多,速度相差無幾,選手之間比拼的是各種細節和常數的處理。後來,我想出了一種速度非常快的方法:

首先使用 A* 加上 “ 卡節點 ” 技術,就是限制 A* 算法搜索過程中每層的節點個數上限,這種算法擴展節點個數在 100 左右。然後,由於上述算法的正確性不能保證,把所有反例打成常量,程序大概 50K 左右。很容易發現,這個程序的速度遠比比賽過程中所有程序的速度都快得多。

最終我的程序以總時間 0.022 秒獲得冠軍, xreborner 和 Savior 以 0.026 分並列第二名。 xreborner 的程序很可惜,如果加入了無解判斷,速度應該比我程序塊, superzn 就更可惜了, superzn 的飄逸程序其實只有 0.020 秒,但是有一個數據錯了。

記得頒獎之後,主持人邀請獲獎選手發言,選手可以通過向前走一步選擇優先發言。這時,我突然感覺大家把目光都聚焦到了我身上,向右一看,由於我站在最左邊沒有注意到右邊的情況,可誰知其他選手都後退了一步,把我留在了看似向前一步的位置。

第二屆 Astar-baidu 程序設計大賽:

第二屆百度程序設計大賽沒有等到 10 月,而是在 2006 年 6 月就拉開序幕。沒有想到的是,第二屆百度程序設計大賽竟然以我在一年前比賽中使用的 A* 算法的名字命名,感到非常榮幸。

記得複賽的題目非常正式,印象最深的要數 xreborner 招牌式的 Zuma ,我推了兩個小時公式纔得到了正確的動態規劃方程,實現之後還由於 TLE 只有 30 分 (100 滿分 ) 。還有 Ying 出的無向圖最小割問題,我用網絡流算法又超時了。不過最後一題,我的程序竟然比 xreborner 優化過的標程還快,真是不容易呀。清華的舍友 RealPlayer 在複賽中表現很興奮,可惜由於一個很小的錯誤沒能進入決賽。

參加第二次百度決賽的選手中有許多熟悉的面孔,清華的同學包括 shell , OpenGL , lympanda 還有 Macsy 。復旦大學也來了很多選手,其中除了 LemonTree 和 Topkiller (沈毅)之外,還有我剛到復旦時見過的 admin 和 funny 的身影。另外 magicpig 和 flymouse 也參加了,而且 magicpig 和我住一個房間,吃飯時記得他把桌上所有人的 Dev 功底全都鄙視了一遍,可惜 PE 不在場呀。比賽前還看到了 Srbga 的身影,據他說是被邀請一起來玩的,其實稍微用小腦判斷一下就知道一定是參與出題的,有了 Srbga 的加盟,相信決賽題目絕對不會是一年前的風格了。

第二年決賽的題目是:著名的俄羅斯方塊。寫程序玩一個 10 列的標準 2 維俄羅斯方塊遊戲。

Srbga 設計了很有特色的記分方法和評分標準。對於記分方法,特別的地方是消去 1 行後沒有得分,而同時消去 2 , 3 , 4 行的得分分別是 3 , 6 , 10 ,記分方法非常鼓勵一次消去多行。評分標準則更奇怪了,有 50 種不同規模的數據,對於每組數據對所有選手的得分進行排名,前 8 名的選手依次得到 10 , 7 , 6 , 5 , 4 , 3 , 2 , 1 分,也就是說,是存在可能性在測試結束之後分數仍然爲 0 的。

比賽過程中,我花了許多時間來分析這個奇怪的評分標準。

對於這種評分標準,常見的策略有兩大類: (1) 所有數據的成績比較平均 (2) 在一種數據風格中特別突出呢。

根據數據描述, 50 個數據可以分爲 10 種不同的風格。參加比賽的總共有 50 名選手,如果所有分數是完全平均分配的話,分數是 31 分,這個數字意義不大。但如果設想分數的 80% 會分配在前 10 名中(根據當時選手的水平,這個假設還是比較合理的),這樣前 10 名的平均分數是 124 分左右,也就是說如果想擠進前 4 ,至少也要 100 分以上,如果想爭取冠軍估計需要 200 分左右。如果選擇一種策略,使得它只在一種數據風格中特別突出,分數只有可憐的 50 分,而且很可能有許多有同樣想法的選手,所以 (2) 不太可取。

在決定選擇比較平衡的策略 (1) 的之後,需要再考慮一個問題,如果最終目標是 150 分,那麼平均分數只需要 3 分,也就是說每個數據可以允許有 5 名選手超過自己。這些必要的分析幫助我明確了努力的方向,面對這種開放性的題目,多分析題目的特點往往可以達到事半功倍的效果。

還有一個重要環節是調整估價函數,機器學習其實是一個很好的策略,可惜我當時不會。其實當時我做的事情,本質上就是人工模擬機器學習,手工調整了 1 個半小時,眼都花了。而且我犯下了一個致命的錯誤,記得記分方法非常鼓勵一次消去多行,也就是說對於平坦的數據,一次消去 1-3 行的權值應該可能設置爲負數,而我只把他們設成了 0 ,使得程序對於平坦的數據分數不高。 Macsy 就考慮到了這一點,只可惜一個很奇怪的技術問題(在 Linux 和 Windows 下的 CLOCKS_PER_SEC 參數是不一樣大的,想使用卡時策略時千萬不能事先把這個數字取出來設置成 CONST )使得 Macsy 沒能成功。

由於 Macsy 和 LemonTree (同樣的技術問題)的出局,我在許多數據中得到了很高的分數,最後的總分達到了是 255 ,領先了第 2 名有 99 分之多。其實現場的許多選手的程序風格相差並不大,可能我唯一多做的事情就是建立了一個博弈樹,多搜索兩層,這樣比直接貪心的程序看得更遠一些。後來事實也證明了,排名靠前的選手大多都是比較平衡的策略。記得 lympanda 洋洋灑灑寫了 1800 多行程序,在其中一種數據中拿到了滿分 50 分。不過可惜 panda 的程序平衡性稍差,總排名進入了前 10 ,但最終只有三等獎。

第二屆 astar-baidu 程序設計大賽,復旦大學獲得了豐收。記得許多復旦的選手由於考試提前回到學校,頒獎儀式的時候二等獎頒獎一片空場。

比賽的住宿條件可以用無與倫比來形容,很感謝 baidu 的大方與細心。記得第一天晚上還有機會和 Ikki 一起打沙壺球,面對球風完全對立的 Ikki 玩得很開心。

Google Code Jam China 2006

大概是 2005 年末,突然看到了名爲 GCJC 的比賽,而且使用的是 TopCoder 的比賽模式,於是就報名參加了。當時估計只參加過幾場 TopCoder 的比賽,帳號還是藍色的, GCJC 第二輪預選賽由於經驗不足差一點就被淘汰了。好在有驚無險地進入到了北京的現場賽。

GCJC 現場的選手中,我覺得至少認識 80% 吧,清華同學就有 7 人: b142857 , fuwenjie , lympanda , Macsy , zig 還有 hyyylr (李老師),復旦的 LemonTree 和 TopKiller 也都來了,浙大也來了許多 TopCoder 上的元老 xuchuan (徐串), sghao126 。

記得,就在 GCJC 決賽的前一天晚上,我參加了 TopCoder 的 SRM 比賽,第一次踩住了 Petr ,不過也消耗了太多的 RP 。晚上的 SRM 比賽中沒有人過 3 題,第二天早上 lympanda 還把我們統統鄙視了一遍。隨後, b142857 還描述他 Challenge 過程中的囧事,由於 500 分題目的返回結果需要使用 long long 類型,所以 b142857 看到一個人提交的程序計算過程中只使用了 long 就果斷 Challenge 了,結果失敗了兩次之後才發現,那個人用的語言是 Java 。

比賽中 250 分題目,簡單的概率問題。我寫完就交了 224 分,竟然是所有選手中最快的。後面的 500 分,我雖然提交是最快的,不過沒有考慮一種情況。打開 1000 分題目之後網絡就開始很不穩定了,時斷時連, 1000 分題目其實算法很清楚,由於網絡原因提交只有 600 分左右了。

Challenge 階段開始時,我打開了房間中 lympanda 的 500 分程序,發現我們兩人的程序基本過程完全一樣。又打開了一個,也一樣。但是在還沒有反應過來的時候, lympanda 的 500 分程序被 Challenge 了,接着我的 500 分也被 Challenge 了。然後就沒有什麼鬥志了,在無奈中等待比賽結束。

比賽結束之後的午飯過程中,我正好坐在 Google 中國掌門人李開復旁邊。午餐快結束時,李開復問起 2 個月前的百度程序設計大賽,突然,鬼使神差地直接問我百度大賽的冠軍是誰?這可是在 Google 的老巢呀,抖死了。我當時真害怕他聽完回答之後直接把我趕下桌 tongueout 。

好在我的 250 分和 1000 分都 Pass 了,由於 TopKiller 的 1000 分超時了,我獲得了第 3 名。冠軍 xuchuan 和亞軍 b142857 都順利通過了 3 題。

POJ Monthly Contest

大概是從 2004 年 8 月開始, POJ 上開始舉行每月一次的有獎月賽。 2005 年的月賽中,每次都有機會同 xreborner , Ying 等高手切磋技藝。從 2006 年初開始,我已經比較熟悉了比賽的題風,連續獲得了許多次比賽的冠軍,並且保持了良好的個人比賽狀態。

記得 2006 年 4 月底,在 POJ 的郵箱裏突然發現了 hawk 的信,他問我五一長假回家的情況。我告訴 hawk 自己定在週五晚上出發。於是,第二天早上就看到比賽安排中: 2006 年 5 月份月賽安排在了週五晚上,太囧了。

後來, POJ 上直接出現了一系列奇怪的定義,但其實結論就是我不能以正式身份參加月賽了。現在這些定義早已成爲笑料了,但是我不參加月賽之後,仍然有 ahyangyi 這樣的選手奪走了絕大多數的冠軍。

後兩屆 baidu 程序設計大賽:

從第二屆開始,我們習慣了在每年 6 月等待 astar-baidu 的開賽。 2007 年最出乎意料的就要數 CS 這個決賽題目了,我在關鍵的買槍環節犯了重要錯誤,太迷戀 AK47 了。祝賀師兄 lympanda , Macsy 還有 shell ,不愧是真金不怕火煉。

第四屆百度大賽我參與了預賽和複賽的命題工作,但是沒有參與決賽的命題。決賽題目是一道關於直升機的題目,印象最深的是 ahyangyi 使用了一個很有進攻性的策略,如果採用淘汰賽,可能就是冠軍了。對我來說,通過現場比賽,有機會和老朋友重逢,並結識了許多新選手是我最大的幸事。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧。今天到了 2007 年初的東京,回顧一下 2007 世界總決賽發生的趣事吧。

ACM-ICPC World Final 2007 —— Mobile Robot 東京決戰

2007 年的東京 ACM-ICPC 全球總決賽在櫻花盛開的 3 月初拉開序幕。成立了一年的 Mobile Robot 憑藉 2006 年 ACM 上海賽區的冠軍,代表清華參加了此次 ACM 盛會。

記得黃金雄教授在杭州 2008 時說, ACM 總決賽的實力分佈由原先的美洲獨霸逐漸轉向了現在的亞歐爭霸。 2007 年,同樣來自亞洲的上海交大具有很強的奪冠實力,歐洲 2007 年雖然沒有頂尖高手 Petr 和 tomek 的參與,但是 ACM 傳統名校 St. Petersburg , St. Petersburg IMFO , Warsaw , Saratov , Petrozavodsk 等都派出了極其豪華的陣容。雖然在 2000 年前後美洲隊伍成績不佳,但是近些年由於衆多歐洲選手的加盟,美洲 MIT 等頂尖名校也在總決賽中表現得非常強勢。

記得,每次世界總決賽之前, TopCoder 的論壇上都會羅列出所有參加總決賽的 TopCoder 選手名單。但是我不是很看重這些數據,因爲在很多次與歐洲選手切磋之後,我發現了自己與歐洲選手相比的一個重大缺陷:我參加各類賽事以來,起初比賽過程中常常受壓力的影響很大,很難正常發揮自己的水平。後來情況有所好轉,在大多數比賽中都能正常發揮自己的水平。可是,令我感到意外的是,許多來自西方的選手在巨大的壓力下,反而表現得極其興奮而能超常發揮出自己的水平。來自西方的各隊,我相信他們只要達到了興奮的狀態,都擁有獲得冠軍的實力。去年上海交大總決賽總結中,他們也提到了自己沒有發揮出應有的水平,而 IMFO 即使在比賽壓力下仍然能夠做出 8 題,可見他們平時訓練實力之強。但是我覺得現場比賽發揮受影響可能是少數中國選手的壞習慣,可能不適合用同樣的思路分析歐洲的頂尖高手。

抵達東京:

出發的前一天晚上,我仍然熬夜參加了 TopCoder 上的 SRM 比賽,竟然是 Petr 出的題目。當時我與 Petr 的 Rating 差距很小,當時我 3 道題目都交出了很高的分數,在 System Tests 之前遙遙領先,但是 500 和 1000 分的題目都由於一些很小的粗心而失敗了。我也失去了在總決賽之前超過 Petr 的大好機會。結果到達日本之後的第二天,吃早餐的時候,我就碰到了作爲教練來到東京的 Petr ,他一看到我就扯前天比賽的事情,汗。現在回想起來,那場 SRM 對我的總決賽之旅確實有不小的負面影響。

抵達東京之後才發現,所有隊伍中,只有我們選擇了與所有志願者衣服顏色相同的清華校色紫色,開幕式過程中,許多隊伍都把我們當成志願者了。

練習賽前一天的晚會很豐盛,大多食物都是中國風格的,水果也非常好吃。晚會期間,我見到了衆多大陸學校的隊伍,當年大陸至少有 15 支隊伍參加總決賽,隨處可以感覺到說着國語的選手。同時還見到了許多 TCCC 上出現過的面孔,隨後發現 ardiankp 也來參加了,我們還聊起了 ACM 在新加坡( ardiankp 是代表南洋理工大學參加的)的情況。類似總決賽這樣的比賽,我覺得選手之間的交流則更重要了,因爲每次總決賽都會集結衆多熟悉的 ID 但陌生的面孔。晚一些之後,我們與北京大學的 T2 一起打牌,隊友 geworm 和 wd.h 都抽籤到了另一方,他們的牌太猛了,在加上我和李文新老師的牌都不好,結果我們慘敗。

從正式比賽的前一天的中午開始,主辦方組織我們遊玩當地的 Disney 樂園。日本 3 月的景色很美,當地人也很熱情,唯一的缺點就是無論用日語還是日式英語都很難交流。我們在 Disney 樂園中主要以觀看錶演爲主,沒有參與過多的活動。東京到了晚上有些冷,我嘴脣都有些結冰了,可是發現路上許多日本女高中生還穿着裙子,仰慕。

正式比賽:

總決賽的隊伍是按照學校的音序排座位的,練習賽時我們發現自己坐在來自荷蘭的上屆亞軍 Twente 大學旁邊,剛打招呼就發現他們 3 人的最低身高也有 190 ,據說荷蘭女子的平均身高也有 180 以上,似乎覺得自己是從小人國來的。

練習賽過程中,我已經絲毫感受不到娛樂的氣息了,現場的緊張氣氛已經籠罩了我們全隊。所有隊伍都在抓緊一分一秒熟悉比賽環境,賽場中敲擊鍵盤的聲音已經完全覆蓋了觀衆鼓掌的聲音。比賽中使用的 PC2 提交系統比想象得穩定,我們努力嘗試各種功能以熟悉機子上的編程環境。東京的總決賽使用了一個形狀奇特的鍵盤,由於當時早已養成了自帶鍵盤的習慣,這次總決賽中奇形怪狀的鍵盤對我編程的速度影響非常大。

總決賽正式比賽在第二天 9 點左右開始, Bill 想盡各種辦法活躍氣氛,不過比賽開始前幾分鐘現場還是靜得可怕,比賽開始 5 分鐘之後,現場就被鍵盤聲籠罩直到結束。我們回顧一下比賽的過程吧,底紋的文字是我比賽後寫下的總結:

這次 World Final 的題目又基本由編程題組成,可能是由於比賽時不夠興奮,比賽全程都非常不順利。

大概從 2003 年開始,世界總決賽的題目風格已經完全倒向以編程題爲主的特點,對此我們早有準備。不過由於時差問題,還有幾天前 SRM 比賽由於錯兩題導致 Rating 跌停對我信心的影響,使我比賽中一直不是很興奮。不過比賽過程中,我們仍然堅定的採用前面提到過的常用組隊模式:

(1) geworm 全程負責讀題,思考算法和出數據;

(2) wd.h 和我在比賽前 2 個小時一起攻簡單的題目;

(3) 2 小時後 wd.h 就開始死磕難題,我主寫程序一直到 3 個半小時左右,結合 wd.h 對難題的把握,大家開始合攻難題。

25 分鐘: Problem A ,簡單地枚舉。可是我生物沒有學好,沒有考慮父母基因的順序問題,錯了一次。

比賽開始時,正常情況我會從 B-I 中間尋找容易上手的題目。可是由於有些緊張,直到 geworm 給我翻譯 A 題目內容時,我還沒有讀懂任何題目,這種情況很少發生。

題目 A 的描述,需要一些必要的生物知識幫助理解,可是這些東西我早已忘記。 geworm 花了不少時間幫助我理解這題,我還是由於沒有考慮父母基因的順序 WA 了一次。不過改過來之後,我們竟然是所有隊伍中第一個通過 A 題的,可見當時很多隊伍也沒有完全放開。

43 分鐘: Problem B ,最長上升子序列。開始算法沒有想好,莫名其妙地錯了一次。

如果說題 A 的 WA 是生物問題,那 B 的 WA 簡直就是莫名其妙。 B 就是最長上升子序列問題,好像剛開始寫時我和 wd.h 都沒有想清楚,寫了一個神鬼莫測的程序, WA 一次之後才改成正確算法。可是當時我們都沒有想到的,總決賽中我們隊伍莫名其妙的 WA 噩夢纔剛剛開始。

97 分鐘: Problem G ,枚舉 + 模擬。這是很扯淡的一題,題目很容易看錯,我們由於看錯題目錯了兩次,等看到 Twente 大學過了之後才重讀題目,找到了正確的理解,浪費了大量的時間。

G 的題目描述確實不是很清楚,許多隊伍都發生了理解錯誤,我們也不例外。不過第 2 次提交錯誤就不能理解了,當時也不知道出於什麼原因又提交了第二次,難道是想先搶一個提交冠軍嗎?當時我們確實受到了開局不順利的影響,這樣做在罰時本身就落後的情況更是下雪上加霜。

146 分鐘: Problem F , BFS 。其實這題是我發揮編程能力的機會,但是我開始用了一個很奇怪的搜索方法,錯了一次才改用 BFS 過了。

在 G 題迷茫而放棄之後,我又嘗試實現了 F 。 F 的第一次 WA 是我們 Final 之行的第三次 “ 莫名其妙 ” 了,我也不知道自己用了什麼一種奇怪的搜索方法竟然過了樣例,還馬上提交了,面對這種情況我有些着急,表現得很不冷靜。好在 geworm 及時提醒,我馬上改成 BFS 過了。在這期間, wd.h 已經實現出了 I 題,並提交了一次,結果是 WA 。

178 分鐘: Problem C ,排序 + 枚舉。這題有一個陰險的地方,就是 theta=0 的情況,還好我們考慮到了,這也是我們唯一一次 AC 的題目了。

C 題的算法其實非常清楚,陰險的情況我們也考慮到了,我終於沒有再搞笑一次,這也是我們唯一一次 AC 的題目了。從通過 C 的時刻講,我們的形式還是很有利的,因爲難度很大的 I 我們已經實現得差不多了。

224 分鐘: Problem D ,數學題。這題本是一道很簡單的數學題目,但是不知出題人怎麼想的,搞了一些沒有任何意義的東西,真是這次題目的一大敗筆。我們開始由於沒有注意三點共線的情況錯了 3-4 次,然後由於 int64 越界又錯了 3-4 次,最後錯了 7 次才 AC 。這題一共浪費了 1 個多小時。

在 BGF 各一次奇怪的 WA 之後,我們又完全陷在了 D 題的陷阱之中,如果順利的話 D 題只需要 15 分鐘就可以寫完,可是我們忘記考慮了 D 題中很多的陰險情況,拖延了 1 個多小時,貢獻了 7 個莫名其妙的 WA 。可是,當時我並沒有想到,這已經是我 AC 的最後一道題目了。

227 分鐘: Problem I ,數學 + 模擬。這題是 Jelly 寫的,有很多特殊情況。

平心而論,我在總決賽上的狀態不是很好,編程速度受到影響,而且有 10 次以上的錯誤提交。最後我們 7 題的罰時高達 1200 多,而上海賽區同樣 7 題的罰時只有 700 多,從這一點上也可以看出當時實在不在狀態。不過, wd.h 很好地執行了我們預定的組隊模式,順利完成了拖後中衛的角色。在我通過 D 題之後,他改正了 I 程序中的最後一個 bug 。 I 題最終也只有我們和華沙兩支隊伍通過,可是說是我們最終能夠獲得亞軍的殺手鐗。記得在頒獎儀式之前,基本上所有選手見到我都問 I 怎麼做,我都統一回答:是胡偉棟做的。

我們依靠 I 題的 AC 首次排在了榜首。比賽進行了 227 分鐘,能夠在 200 分鐘之後獲得領跑的機會,我首次看到了奪冠的希望,上海和西安賽區的歡呼場面一次又一次從我眼前閃過。當時只有華沙大學通過 6 題,其他隊伍都還不超過 5 題。

可是幸福只持續了短暫的 3 分鐘,我們由於罰時太多而被華沙反超,華沙大學通過第 7 題時華沙隊員的反應幾乎瘋狂, ICPC 的工作人員也用照片記錄了這一時刻。

Problem E ,我們的算法應該是正確的:二分答案 + 最短路。但是不知程序犯了什麼錯誤,沒有 AC 。

Problem H ,很複雜的幾何題目,我們的算法是:掃描。但是不知程序又哪裏寫錯了,結果是 WA ,不是 TLE 。

雖然在接下來的 73 分鐘時間內我們沒有再過題,不過我們仍然拚殺到了最後一刻,拼盡全力而無怨無悔。無論是 E 還是 H ,我們都想出了正確的算法,並且成功寫完了程序,但是 Judge 給出的結果一直是 WA 。我們不斷測試數據,並修正了一些 bug ,但仍然不能通過第 8 題。在這種情況下的穩定過題能力我們確實特別沒有訓練過,華沙能夠通過 8 題的超強實力確實很讓人敬佩。比賽剛結束時, Petr 還特地趕來問我們有沒有通過第 8 題, ICPC 的工作人員碰巧留下了照片。

當時我很希望能夠借他的運氣得到一個 Yes ,不過 PC2 還是不斷返回 WA 直到最後。

後來, E 題就成了我寫計算幾何題目的一個巨大的心理障礙,直到 2 個月前在 Proxima 的一次訓練中,在隊友的支持下,我終於成功通過了一個更強版本的 E 題(題目在 UVA 上,題號是 11425 ,這題至今 2009.1 也還只有我和東京冠軍隊的 marek 通過)。

Problem J ,這是一道很複雜的算法題目,現在我還不能證明算法的正確性。更重要的是這題很容易實現一些看似正確的算法,可能沒有做這題是我們這次比賽的唯一成功之處。

I 的算法大致如下:

(1) X_i = the mininum cut between V_i and V_0.

(2) while (the graph is not empty)

{

(3) m = min(X_i).

(4) remove all nodes V_i whose X_i=m.

(5) let X_i = min( X_i , m+ the mininum cut between V_i and V_0 ).

}

(6) return X_1.

這裏提一個公開的祕密,最後顯示華沙大學的結果時,他們成功通過了 E 題,可是比賽過程中,我們並沒有看到他們掛起藍色的氣球,不知道來自浙江大學或者中山大學的選手能不能仔細回憶一下,當時你們應該坐在他們旁邊。

頒獎:

最終,華沙大學以通過 8 題的成績獲得冠軍, Mobile Robot 通過 7 題總用時 1200 分鐘獲得亞軍。整場比賽,我們克服了開局的種種不利因素,成爲全場第一支通過 7 題的隊伍,亞軍也是一個非常可喜的成績了。由於華沙大學不來自亞洲,我們同時也獲得了亞洲冠軍。

頒獎儀式之後的表演很精彩,印象最深的要數那位 “ 神偷 ” 了,他在觀衆面前不斷施展 “ 妙手空空 ” ,觀衆掌聲不斷。記得表演結束後大家等電梯時,那位演員從我們身邊走過,我們都連忙確認自己的錢包和手機。 ACM-ICPC 東京總決賽在一片片掌聲中落下帷幕。

總結:

ACM-ICPC 總決賽結束後, Mobile Robot 又恢復了平靜。 Mobile Robot 成立以來共獲得了兩個分區賽冠軍和一個總決賽亞軍,從那之後 Mobile Robot 就宣佈解散了,也許唯一的遺憾就是沒能獲得一個真正的世界冠軍。賽後,黃金雄教授也來向我們祝賀,從他的言語中,我們也感受到了一絲揮之不去的遺憾。

東京總決賽的幾天裏,我有機會結識了許多國內外朋友,也是這次日本之行的一大收穫。同時也感謝衆多 ACM 選手一年來對我們的關心和支持,當時 bbs.pku 上留下了一個很長的帖子,讓我永生難忘。

在現場比賽中,我數次與歐洲選手直接交手,對他們的特點有一定的瞭解:

(1) 歐洲選手的編程能力很強,很適應總決賽現有的題目風格。有些歐洲選手在 notepad 裏寫程序,然後直接提交的事蹟絕非傳說。

(2) 歐洲選手對於算法的靈活運用能力強,但是對於一些比較深的算法瞭解不多。例如此次總決賽的 J 題。

(3) 許多歐洲選手的現場抗壓能力很強,即使在最後時刻仍然可以發揮出自己的水平。

在總結過復旦和 Srbga 出題的風格之後,總結一下我理解的總決賽題目風格吧:

(1) Srbga 大哥出的題目和世界總決賽的題目風格近似,題目對編程能力提出了極高的要求。相比之下大多數題目對算法的要求不高。

(2) 總決賽題目對算法的考察範圍非常廣,但是對於某特殊的算法要求不高。

(3) 總決賽題目的時間限制很寬,出題人很提倡一題多解。而且數據沒有想象得苛刻,隨機算法有用武之地。

東京的總決賽已經結束快 2 年,今年寒假結束之後,我又要準備踏上總決賽征程了,希望這次我們 Proxima 能做的更好,將總決賽名次提高一位。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧。今天總結一下國際個人賽場吧。

國際個人賽場 —— 三大賽事

ACM-ICPC 總決賽結束後, Mobile Robot 就宣佈解散了,也許唯一的遺憾就是沒能獲得一個真正的世界冠軍。宣佈退役 ACM 之後,我仍然連續參加了那之後的每一場世界範圍的現場編程比賽,按照時間先後分別是: TopCoder Open( 簡稱 TCO)2007 , TopCoder Collegiate Challenge ( 簡稱 TCCC)2007 , TCO2008 以及 Google Code Jam( 簡稱 GCJ)2008 。每次比賽,我都度過了一段美好快樂的時光。

TopCoder 公司與三大賽事:

TopCoder 公司大概在 9 年前成立,成立的原因有些讓人匪夷所思,據說公司創立者原來是另一家 IT 公司的大股東,在把原來公司的股票轉手之後換了一筆錢,開設了 TopCoder 公司。然而 Topcoder 和原來的 IT 公司有一個重要協議,就是 Topcoder 在創立之初的兩年內不得從事軟件開發的工作。於是 TopCoder 在前兩年時間內以類似競賽的方式從事軟件開發的活動。經過 9 年的發展,現在 TopCoder 公司已經基本由算法競賽轉向軟件開發了。

TopCoder 公司除了在網上舉辦 SRM 之外,每年還舉辦 TCO 和 TCCC 等現場賽事(當然還有 TCHS ,不過規模比較小,參與面也不是很大), TCO 和 TCCC 分別在每年的 6 月和 11 月舉行,每次大賽都能匯聚衆多國際編程高手。另外, Google 公司從 2000 年開始,先在各大洲舉辦名爲 Google Code Jam 的比賽,從 2002 年開始也舉辦全球範圍的 Google Code Jam 。於是這些年來,大家一直把 TCO , TCCC 和 GCJ 稱爲三大賽事。

2007 年之前的 GCJ 都是使用 TopCoder 的比賽形式, Topcoder 的算法競賽有點類似於 IOI , ACM-ICPC 之類的競賽,題目是同一個類型的。每次比賽三道題目,一般分數分配爲 250-500-1000 ,比賽分爲 Coding , Rest , Challenge 和 System Test 四個階段,時間各是 75 分鐘(現場比賽 85 分鐘), 5 分鐘, 15 分鐘(現場比賽 10 分鐘)和不定。

TopCoder 的現場比賽都由 3 個階段組成:所有選手被分爲 3 個組(稱爲 Room1 , 2 , 3 ),每組分別進行半決賽,每組前 2( 或 3) 名直接晉級決賽, 3-6 名晉級 wildcard 比賽, wildcard 比賽 12 人中的前兩名填補決賽的最後 2( 或 1) 個名額,決賽由 8( 或 10) 名選手參加。由於三大賽事的比賽形式相差不大,每次現場決賽的選手中總是有許許多多熟悉的面孔。

三大賽事的波盪起伏:

可能細心的同學能夠發現疑問,在文章最開始的一段中,我表明自己在 2007 年之後沒有錯過任何現場賽事,那爲什麼沒有 GCJ2007 呢?其實原因很簡單, Google 公司在 2007 年全年中只舉辦了面向美洲的比賽,沒有舉行面向全世界的公開賽。 GCJ2007 的擱淺也使得整個 2007 年只有 TopCoder 公司獨自舉辦世界大賽。

但是,當大家以爲 GCJ 將在記憶中淡去的時候, GCJ2008 重新登陸,而且新的比賽環境與形式給選手以煥然一新的感覺。這裏先談談自己對這種新比賽環境的看法吧:

GCJ2006 仍然使用的是 TopCoder 標準形式,也就是說和 TCO 以及 TCCC 完全一樣,用一句話概括就是 Coding-250-500-1000-Challenge-SystemTests 。

GCJ2008 比賽環境結合了 ACM , TopCoder 還有 IPSC(ipsc.ksp.sk) 等多種比賽的特色。

(1) 每道題目分爲 Easy-Hard 兩組數據,並且數據可以下載到本地,這點好像與 IPSC 很相似,另一個與 IPSC 的共同點就是,不限制選手使用的編程工具,包括肉眼觀察或者人工搜索。

(2)Easy 數據則和 ACM 非常近似,即時提交評測,並且也設定了每次失敗提交加 4 分鐘的罰時。

(3)Hard 數據則更像 TopCoder 的形式了, Hard 數據由於是統一評測, System Tests 可以有效

地把懸念保留到最後一刻。

GCJ2008 的比賽形式是一種大膽的嘗試,並且也已經有了很理想的結果。

另外,值得稱讚的是, GCJ2008 中首次使用了分各大洲進行當地現場半決賽的賽制。使得排在前 500 名的選手得以參加各大洲的半決賽,也拉近了 Google 公司與選手之間的距離。從另一個角度來說,各大洲半決賽的方法很有效保證了決賽選手的水平。平心而論, TopCoder 現場比賽前的最後一輪網絡淘汰賽對選手的壓力很大,就連 Petr 在 2007 年都直接來了一個 “ 滑鐵盧 ” ,連現場賽都沒有進。而現場比賽的公平程度遠超過網絡賽,所以通過現場賽決定決賽選手可以一定程度上提高決賽選手的水平,至少我個人很贊同這種做法。

擱淺的比賽無獨有偶,可能是受到了 2008 年全球經濟危機的影響, TCCC2008 也停辦了。而且我們都覺得, TCCC2007 很可能是 TopCoder 舉行的最後一次 TCCC 了,當然 TopCoder 這樣做沒有不合理的地方。

TCO 則相對穩定一些,就連每年舉行的地點都不變, TCO 連續 3 年在著名的賭城 Las Vegas 舉行。今年應該也不會改變地點。

三大賽事的舉辦,我覺得選手最大的受益就是,比賽提供了一個到美國免費遊玩的機會。我先後去過 7 次美國,其中 6 次都是參加編程比賽。通過比賽的機會,我們得以開闊眼界,結交朋友。我個人真心希望三大賽事能夠繼續舉行,但是 2009 年秋天的 TCCC 和 GCJ 很可能同時停辦,這也是一個不可迴避的問題,讓我們拭目以待吧。

美國之旅:

從 2007 年以來的 4 次現場比賽,雖然每次比賽過程中都有一些遺憾,但是現在回想起來都有不盡的樂趣。

TCO2007 是我第一次到達賭城,一下飛機就看到很多賭場 (CASINO) ,可誰知 TCO2007 整個比賽過程就是一場巨大的賭博。我當時由於不熟悉 Texas Hold'em 的規則,在半決賽中搞錯了 Flush 和 Straight 的大小關係,結果初上賭場就傾家蕩產而被淘汰出局。 TopCoder 比賽中竟然出賭博有關的題目,果然有 Las Vegas 的特色呀。不過在賭場裏,我仔細研究了許多賭博遊戲的規則,然後寫了幾個程序計算賭博的期望,但是發現標準概率模型下所有遊戲的期望值全是負數(其實挺顯然的),於是,也就以娛樂爲目的和 lympanda 切磋了一下。

如果說 TCCC2006 的 Room1 是中國的勝利, TCO2007 的 Room1 則是中國的失敗了,雖然 Ying 和 lympanda 都進入了 wildcard ,可是都由於一些小失誤輸掉了這次賭博。賽後 lympanda 請我去牛排館吃飯,後來那個牛排館也成爲每次 TCO 比賽我們中國選手的主要聚會地點。

TCCC2007 的小組賽還比較順利,我輕鬆擊敗了 gawry , Per , marek.cygan 獲得小組第一挺進決賽。可是決賽中,我爲了提高速度以超過 Petr ,再加上有些緊張,最後 500 分和 1000 分兩題又都掛了,落到了第 5 名。 TCCC2007 地點設在了奧蘭多,比賽結束後我們到附近的 Disney Land 去玩,那裏的驚險遊戲比國內刺激得多,有些遠遠超過我的極限,我們一行人一直玩到深夜才返回。許多選手還一起到奧蘭多魔術隊主場觀看了 NBA 現場比賽,可惜最後一節成爲了垃圾時間。

TCO2008 我也依靠飄逸的 1000 分題中 800+ 分的提交闖入決賽。決賽前我還和 visualage 聊天,誇耀自己從來沒有所有題目全掛,更沒有拿過負分。可是在隨後的決賽中,這兩個 “ 夢想 ” 就都實現了, PE 對我的評價是太緊張了。基本每次 TopCoder 現場比賽都能見到 PE ,誰知他每次懷疑我某些題目的正確性的時候,我的程序就一定是錯的,如果下次我參加決賽,您就不要再看我程序了吧(呵呵,開個玩笑)。

不過在決賽 Challenge 階段的最後時刻,我從第一視角目睹了 Petr 和 Tomek 的巔峯對決。在還有 15 秒鐘結束時 Petr 還落後 Tomek 大概 30 分左右, Petr 成功 Challenge 了一個超過了 Tomek ,但是 Tomek 利用短短的 10 秒鐘也提交了一個成功 Challenge 又超了回來,誰知 Petr 得到這個信息之後又提交了一個 Challenge ,可是運氣稍差,如果那個數據用來 Challenge 我的程序的話, Petr 就能夠在最後 1 秒再次奪回冠軍的位置。能夠到最後一秒還能有機會成功翻盤的一定是神一般的人物,能夠把神一般的人物逼到最後一秒的也一定是神一般的人物,兩個神一般的人物你來我往,爲大家上演了一場精彩的比賽。

歐洲獨霸:

又一次引用黃金雄教授在杭州 2008 時說的話, ACM 總決賽的實力分佈由原先的美洲獨霸逐漸轉向了現在的亞歐爭霸。但是,我根據這些年的比賽結果發現,從 2006 年開始,團體比賽和個人比賽,特別是個人比賽,歐洲選手一直保持着絕對的霸主地位,亞歐爭霸的說法實在有些牽強。

從 2005 年開始,幾乎所有三大賽事的冠軍都是歐洲選手。成績最好的要數俄羅斯,俄羅斯選手以 Petr , andrewzta 等爲代表。俄羅斯選手訓練刻苦,編程能力極強。歐洲的另一霸主就是波蘭,波蘭選手具有很強的靈氣,以 tomek , marek 以及 Eryx 爲代表,程序設計在他們手中體現出了藝術氣息。

前幾天我也看到關於取消 NOIP 保送 資格的文章,我沒有發表評論,因爲我沒有看懂,爲什麼文章裏把保送和保送資格混爲一談,讓人覺得哭笑不得。這裏我對 保送 資格還是想法不多,不過想比較一下我們中國選手與歐洲選手思維能力上的差別。

在高中時,吳文虎老師就常說中國選手的 IOI 成績很優秀,的確這幾年從 IOI 成績上看,中國是絕對的霸主。可是 ACM-ICPC 的成績,俄羅斯和波蘭等強隊的成績卻遠在中國之上。於是我們總結的原因是:歐洲選手的編程能力強。我非常同意這個說法。

但是 “ 歐洲選手的編程能力強 ” 的說法並不說明他們的算法能力弱,相反他們的思維素質非常高,他們具有非常正統和嚴密的思維方式,體現出經過長期訓練的思維能力和素質。

我覺得中國的 “ 高手 ” 和許多通過高考進入名校的 “ 神人 ” ,在大學之前接受的教育都是以選拔爲目的的,並沒有太多針對思維方式和能力的訓練。記得小學要考重點初中,初中則拼搏重點高中,高中期間則夢想名牌大學,而在學習期間,我們並沒有太多機會訓練自己的思維能力,至少在我的中學階段是這樣的。雖然很多高中已經竭盡全力通過類似研究性學習的方法鍛鍊我們的創新能力,但是仍然不能改變選拔性考試 “ 高考 ” 這一事實。而在與西方選手交流的過程中,我覺得許多思維能力優秀的學生很早就有機會接受系統的思維能力訓練,尋找最適合自己的思考方法。我一次有機會看 Eryx 留下的草稿,發現他考慮問題有非常嚴密的過程,從理解題目到想出算法每步都有根有據,並不是隨機碰撞的結果。

現在歐洲選手與我們相比,思維能力上也並沒有劣勢。我有幸在投身 OI 競賽之後,得到許多機會與其它選手交流,學習他們的思考方法,努力鍛鍊自己這方面的能力,試圖與衆多歐洲選手對抗。

Mountain View 登頂:

GCJ2008 在 Google 總部 Mountain View 舉行,賽前我想用 Ying 的一句話來表達我對比賽奪冠的渴望, “ 我雖然獲過很多獎,但是缺少一個世界冠軍 ” 。早在 GCJ2006 ,我就擁有機會獲得冠軍,但是在失去那次機會之後一等就是整整的兩年。

比賽開始不久, bmerry 的強勢起跑使我逐漸失去了奪冠的念頭,只得一心做好眼前的題目。 bmerry 在不到 2 個小時的時間裏就做出了除了 C- Hard 以外的所有題目,他只要在最後一小時做出 C- Hard ,就基本上可以鎖定冠軍了。

不過我克服開場的不順利之後,磕磕碰碰地在 2 小時過 5 分順利通過了 E-Easy 和 E-Hard 。擺在我面前的只有 B-Hard 和 C-Hard 。 B 題和 C 題相比之下, B 題我已經有了一定的想法,可是 C 則是完全沒有想法。於是我決定先做 B , GCJ2008 的 B 題簡直是我的剋星,我先後用了 100 分鐘時間做這題都沒有結果,可以說當時狀態很差。大概到了 2:40 的時候,我查看 board 時突然發現了一件令人窒息的事情, bmerry 已經嘗試了 C-Hard 並且超時了。由於 C-Hard 的分數略高於 B-Hard ,我最後想要超過 bmerry 就必須做出 C-Hard 。果斷放棄 B-Hard 之後,並沒有想出 C-Hard 的方法,寫了一個搜索程序但是心裏很沒底, Hard 數據的提交時限是 8 分鐘,於是到了 2 小時 52 分的時候,我毅然打開 C-Hard ,用搜索的程序運行 C-Hard ,在焦急的等待之後,程序在運行了 1 分多鐘以後神奇地運行結束了。我依靠搜索方法通過了 C-Hard ,一舉超過了 bmerry 。 1 分鐘後 zhuzeyuan 也做出了同樣的題目,超過了 bmerry ,由於罰時排在第 2 名。我和 zhuzeyuan 還有 bmerry 比賽過程中都有不小的失誤,我很有幸把失誤的損失降到了最低點,終於獲得了第一個世界比賽的冠軍。

這次 GCJ 的題目有非常詳細的解答,可以在比賽的鏈接裏找到。 GCJ2008 的比賽結果從一定意義上,打破了歐洲選手多年的獨霸場面。加上原籍南非的 bmerry ,前五名中都沒有出現歐洲選手的名字,這也是在多年現場比賽中沒有出現過的。

這一年,我很高興看到 OI 選手中出現了 ahyangyi , yuhch123 , Loner 等各方面都極爲出色的新人,真心希望你們能夠早日適應大學的學習生活,再創佳績。

衆多新人的加盟,大大提高了清華 ACM 團隊的實力。在 2008 年,清華大學 ACM 隊創紀錄地獲得了 4 個分區賽的冠軍。明天最後一篇回憶中將分享 ACM-2008 中發生的趣事。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧。最後是 2008 年的杭州復出。

2008 年 ACM-ICPC —— 杭州復出

2006 年 ACM-ICPC 總決賽結束後, Mobile Robot 就宣佈解散了,也許唯一的遺憾就是沒能獲得一個真正的世界冠軍。宣佈退役 ACM 之後,我並沒有完全與 ACM 絕緣,每次 TopCoder 大賽之前還常常做一些 ACM 比賽調整狀態。記得 08 年初,我也全程觀看了總決賽,不過沒有想過復出。


杭州復出: 
一切事情要從一個 zhuzeyuan 的電話說起,時間是 11 月 8 日 晚上 10 點左右,當時我正在參加 UVA 在線比賽而爲 GCJ2008 作準備。 zhuzeyuan 在電話裏首先告知我 Loner 車禍的事情,好在現在 Loner 已經痊癒了,當時確實很擔心。隨後, zhuzeyuan 向我介紹了 2008 年 ACM 比賽的進行情況,當時北京和哈爾濱賽區已經結束。然後,邀請我加入 Proxima 參加杭州賽區的比賽。我想當時答應的原因主要有 3 個: 
(1) 我個人很喜歡 Coding ,雖然退出 ACM 已經快兩年了,但是還經常參加個人比賽。剛剛結束的 GCJ2008 中國區半決賽,出人意料的奪冠增強了我的信心。另外, ACM 這樣長達 5 個小時的團隊比賽造就了很特別的環境,賽場上的氣氛和激情是做裁判教練或者參加個人比賽中無法體會到的。 
(2) 3 年前的 2005 ACM 杭州賽區,我留下了我大學生活中的一大遺憾。對於杭州 2005 的慘敗,我一直想尋找機會從那個跌倒的地方爬起來,徹底擺脫紫金港校區留下的陰影。 
(3) 其實還有一個原因就是我家在杭州,而且在本科期間我也曾經到杭州電子科技大學做過關於 ACM 的報告, lcy 老師的熱情給我留下了深刻的印象。 
對於 Loner 的車禍,我也覺得非常意外。這也是對於我們常年在校園騎自行車裏橫衝直撞的警示。 Loner 現在能夠恢復得這麼好,我們都很高興,祝你明年 ACM 好運。 
加入 Proxima 的手續很順利,教練鄔老師對我復出想法的回答簡單扼要:研一學生可以參加 ACM 比賽。 
Proxima 的另外兩名隊友分別是 zhuzeyuan 和 zhouyuan (周源),我加入 Proxima 之後,新 Proxima 先後進行了 3 次訓練比賽,隨後就出發到杭州電子科技大學參加 2008 年 ACM 杭州賽區的比賽了。 
當時,我通過許多網上資料和 zhuzeyuan 的描述瞭解了當時清華的戰績。到杭州賽區之前,清華的 What ’ s Up 和 IronGods 已經分別獲得了哈爾濱和北京賽區的冠軍。其中 IronGods 還獲得了哈爾濱賽區的亞軍, What ’ s Up 則一起來到杭州參加比賽。 Proxima 在杭州賽區之前已經參加了北京賽區的比賽,成績是第二名。就當時的形勢講,我們沒有資格考慮太多事情,如果想保留懸念就必須獲得杭州賽區的冠軍。


杭州賽區現場賽: 
在杭州賽區練習賽那天的上午,我們抓緊一切時間進行了模擬訓練,選擇的題目是 NEERC 的題目。題目難度有些大,我們做滿整整 5 小時,直到 12 點 50 才急忙去吃午飯。結果很晚纔到達比賽場地,到時候練習賽已經開始很久了。希望我們的遲到沒有影響旁邊隊熟悉比賽壞境。 
杭電賽場的環境很好,在賽場裏我找回了 2006 年上海賽區的感覺。隊伍之間的空間很寬敞,電腦桌也很大,足以讓 3 個人在上面一起推導公式。馬上就見到了 lcy 老師,不過他帶來了一個不太好的消息 —— 不允許自帶鍵盤。好在杭電提供的鍵盤很標準,對我們影響不大。 
正式比賽在第二天早上 9 點開始,回顧一下比賽的過程吧: 
在 Proxima 隊中,比賽開始時,仍然由我準備編程環境,然後從中間開始讀題。我馬上發現了 D 是一道看似簡單的題目,並且也注意到了這句話:

WARNING: a naive algorithm might not be sufficient to solve this problem.

但是沒有想到的是 BFS 算法也算是 naive algorithm ,我交出了全場第一個提交,結果是理所當然的 TLE 。不過那句 WARNING 稍微有些飄逸。

zhuzeyuan 發現 A 是簡單題目,於是我馬上寫 A 。

19 分鐘, A :判斷兩張圖的修改距離。枚舉全排列,統計即可。

A 是最簡單的題目,由於開始 D 的耽擱,我們大概是全場第 4 個出題的隊伍。

接着, zhouyuan 發現 J 也很簡單,於是我轉向 J 。

28 分鐘, J :允許刪點的並查集問題。通過添加新點的方法實現刪點。

過了 J 之後,排名暫時上升到第一位。隨後, zhuzeyuan 發現沒有新題可寫,於是就開始寫 C ,過程中,我和 zhouyuan 發現 G 比較簡單,於是插空寫 G 。

50 分鐘, G :簡單圖論問題。開始刪點判斷錯誤造成 WA 了一次。

59 分鐘, C :高精度計算和素數判定問題。這題是 zhuzeyuan 寫的。

不到一個小時就通過了 4 題, Proxima 獲得了一個很好的開局。對於杭州賽區難度的題目,能夠在第一個小時通過 4 題已經很順利了。對於許多分區賽中會出現更多的簡單題目的情況,有時能夠做到一小時 5 題。但是一小時 6 題實在太難了,記得我們在一次訓練比賽中做到了一小時 6 題,已經是我們的能力極限了。

接下來我實現了一下 B ,可是由於發生了理解錯誤,計算結果與題目要求計算的結果直接存在重複排列問題,只好把程序放在一邊。

隨後, zhuzeyuan 開始實現 H ,提交之後我開始寫 F 。

95 分鐘, H :計算幾何,如果使用 O(n2) 的算法需要注意常數不易太大。

105 分鐘, F :自動機判斷相等問題,通過計算差乘的方法能夠在 O(n2*|Sigma|) 內解決

H 的提交等了很久, H 的 Yes 出來後不久我就寫完了 F ,提交之後也 Yes 了。大概在 2 個小時左右我們做出了 6 題,其實如果不在 B 上浪費時間能夠更早一些。在 2008 杭州賽區,我們又一次獲得了 6-4 的領先優勢。

下面我們面臨一個比較困難的狀況, E 和 I 看似都比較複雜,但明白題意的 B 和 D 都沒有想出算法。 2008 年杭州賽區的題目中,基本沒有中等難度的題目,所以我們通過 6 題之後就直接進入了比賽後期。當時我們分了一下工,我決定死磕 D 題, zhouyuan 負責推 B 題的公式。 zhuzeyuan 嘗試新題目 E 或者 I 。

我的工作進行很不順利,先實現了一個普通的 A* 算法,由於優化得不好還是 TLE 。現在回想起來, D 題標準 A* 算法中使用的那個優化還是挺巧妙的,至少很有藝術感。我放棄 A* 算法之後, zhouyuan 似乎已經推好了 B 題的公式,開始幫助我實現 D 題。

163 分鐘, D :狀態最短路徑問題,通過 A* 算法加一些優化可以輕鬆通過。

zhouyuan 提出了一個很重要的優化方法,先通過解方程的方法判斷是否有解,在確認有解的情況下使用雙向廣度優先搜索,程序寫好之後又 TLE 了。不過我覺得運行時間已經差不多了。於是,我使用了卡節點的方法,終於在第 5 次提交通過了 D 。 D 題我們用了大概一個小時左右。這時 What ’ s Up 早已通過 5 題,不過由於他們卡在 H 題上,我們仍然以 7-5 領先。

zhuzeyuan 確認 E 和 I 比較複雜之後,我們開始合攻 B 題。 zhouyuan 其實受到了我原先錯誤算法的誤導,他得到一些公式來計算繁衍函數,通過繁衍以及原先程序的結果得到正確結果。不過,從當時的形式看,這樣也是很不錯的選擇。

程序很快就寫好了,提交之後又是奇怪的 TLE 。 B 題的 TLE 和 D 的 TLE 本質完全不同, B 題我們算法的複雜度是 O(n4) 的,對於 n<=20 的數據範圍,時間上應該沒有問題。於是,我生成了 100 組測試數據,發現總共只需要 1 秒左右。

在 B 題的這一點上,我覺得命題人做的很不合理,雖然此題存在 O(n3) 的算法,但是既然把範圍出到 20 ,就應該允許 O(n4) 的算法通過。可是命題人一共疊出了 6000 組測試數據,使得我們的程序超時了。而且在 Clarify 中的回答是 1000 多組,我們優化程序之後還是一直 TLE ,當時我們怎麼會想到是 6000 多。至少這裏的範圍 20 極具誤導性。幸好, zhuzeyuan 及時想出了一個解決方法 —— 打表。由於對程序沒有信心,打表的 15 分鐘時間內我們 3 人都只得通過手工計算簡單數據來確認程序的正確性。

236 分鐘, B :比較複雜的動態規劃,需要考慮 4 種情況。

打完表之後提交終於得到了第 8 個 Yes ,時間是 236 分鐘,距離封版只有 4 分鐘。由於 6000 組的陰險數據,我們從第一次提交 B 題到通過 B 整整用了 50 分鐘,而且是 3 個人一直在一起做。

封版時,我們仍保持了 8-6 的領先優勢。但是接下來,我們犯下了杭州 2008 最大的錯誤,如果類似的錯誤在總決賽中出現,我們將很可能失去領先位置。當時我們沒有看到港大掛起 E 的氣球,於是在 E 和 I 中選擇了 I ,結果深深地陷在了 I 的無底洞中,直到結束都不能自拔。

I :模擬題,需要考慮的情況比較多。

E :計算幾何。計算半平面的交。

現在回想起來, E 題的難度遠沒有 I 題大,我們錯誤估計了 I 的難度。非常敬佩賽場上通過 E 題的港大和 I 題的湖南大學,你們不愧爲射鵰英雄。

清華 2008 戰況:

2008 年,清華延續自己在 ACM 大陸賽區中的霸主地位, 4 支不同的隊伍獲得了創紀錄的 4 個不同賽區的冠軍。分別是:

1. What ’ s Up —— 哈爾濱賽區冠軍

2. IronGods —— 北京賽區冠軍

3. Proxima —— 杭州賽區冠軍

4. ZCS —— 成都賽區冠軍

從 ACM 的規則上講 4 支隊伍都獲得了進軍總決賽的資格,清華總決賽隊伍的選拔過程在成都賽區結束的第二天就開始了。

從我的角度描述另 3 支隊伍的情況吧:

What ’ s Up 是清華第一個獲得冠軍的隊伍,杭州賽區的過程中,他們以 amber 主寫程序的模式進行,在比賽開始階段體現出了很強的衝擊力,不過卡住 H 後的慌亂略顯出組隊模式的缺陷。雖然他們在杭州賽區之後就選擇放棄了總決賽資格的爭奪,但是我們都深知他們的實力。後來 What ’ s Up 的成員擔任了 PK 比賽的裁判工作。

ZCS 由剛進入清華學習的三名大一學生組成,成員是 yuhch123 , Cheryl 和 ScaleRhyme 。我參加 Proxima 之後沒有和 ZCS 交過手,不過在 Ural 和 SGU 上比賽時看到過 ZCS 的身影。在杭州賽區之後, ZCS 在成都賽區創造了 7/7(7 提交 7 通過 ) 奇蹟,不過和北京賽區相似的是後期略顯經驗不足。隨後, ZCS 沒有參加校內 PK 賽。

IronGods 的組成是 OpenGL , ahyangyi 和 ghy 。在 IronGods 成立之初,我一直很看好這支隊伍。哈爾濱賽區結束後,記得 ahyangyi 還來和我抱怨比賽中的失誤,那道高精度題目確實有些過於複雜(呵呵,不過至少數據沒有錯誤)。北京賽區的情況,我是事後聽 dzx 介紹的, IronGods 依靠最後一小時的穩定發揮,通過 3 題,一舉壓倒 Proxima , Carriage 和 ZCS 獲得冠軍。可是幾天後,我驚奇的發現自己需要面對強大的 IronGods 了。

IronGods 的組合與新 Proxima 驚人得相似, IronGods 的 OpenGL 與 ahyangyi 還有我和 zhuzeyuan 都是 TopCoder 上的 Target (中國一共有 7 個 Target ,另外 3 個是前輩 haha , lympanda 和 ZCS 隊中的 yuhch123 ,看好 zhoujie 成爲第 8 個,加油呀!),他們的編程能力與我和 zhuzeyuan 不相上下。從 TopCoder 的成績上看,我們兩人的速度略快。

另一名隊員 ghy 和 zhouyuan 都很擅長思考算法, ghy 結束 OI 時間比較短,狀態保持得很好, zhouyuan 對於深入的算法瞭解比較紮實(北京的 A 很贊呀!)。

從配合上說, IronGods 組隊時間長,配合方面比我們默契許多。我們重組後雖然也進行了一些訓練,不過在比賽中普遍交流偏少,特別是我和 zhouyuan 的交流,在後幾場比賽中才有些成功的配合。

不過從穩定性角度看,我們稍占上風, TopCoder 上的 Volatility 值至少可以說明一些。而且 ACM 比賽時間長達 5 小時,穩定性的要求應該比 TopCoder 還高一些。

清華校內 PK :

後來, zhuzeyuan 代表 Proxima 與 IronGods 協商之後,大家決定採用三局兩勝的賽制,並定下了 3 場比賽的時間和題目安排。

關於總決賽隊伍的選拔,我個人非常不贊成直接指定,可能與我的一些經歷有關吧。已經進入研究生學習的我,對參加總決賽已經沒有兩三年前的激情了。不過我個人的觀點是,如果學校指定,我對於 4 種結果都可以接受;如果進行 PK 選拔,賽場上我一定拼盡全力。

兩場 PK 過程中,我們都在 bbs.pku 上發佈了現場的即時排名情況。由於清華 ACM 團隊有嚴格規定要求對兩次 PK 中使用的題目保密,我這裏就只留下了比賽的大致過程。

第一場 PK ,時間和吉隆坡賽區完全相同,過程大致如下:

Proxima 啓動比較快,到 2 小時左右就獲得了 5:2 的領先優勢。

題 F 是這場比賽中我們最大的失誤, F 浪費了很多時間,而且最後都沒有過。

IronGods 利用 Proxima 卡住 F 的時機連追 4 題,以 6:5 反超。

發現 IronGods 反超之後,我又嘗試了幾次 F 題,但還是不能通過。比賽還有 70 分鐘結束,而且我們手上並沒有其他題目。 zhuzeyuan 在關鍵時候毅然決定開始寫 J ,記得他說的一句話是 “ 沒有時間了,我必須開始寫了 ” ,當時形勢不容樂觀。好在 J 成功 1Y ,士氣大振。

Proxima 隨後連過兩題重新佔據 7:6 優勢。

最後, IronGods 追成 7:7 平,比賽又打得難解難分。

IronGods 最後時刻也還有機會,我們又一次目睹了 IronGods 的絕地反擊實力,可能他們最後做 H 的選擇值得商榷。

第一場 PK 過程中兩支隊都有明顯失誤的時期,我們由於失誤在中期,所以罰時較少。最後依靠罰時險勝,在 PK 中佔得先機。

第二場 PK ,時間設在 12 月 25 日 的晚上進行,題目編號從 A 到 L ,共有 12 題之多。第二場 PK 比前一場進行得更激烈,過程中兩支隊伍都長時間保持了很好的狀態,比賽過程中多次交換領先位置:

開局 Proxima 起步略快, 65 分鐘就通過了 5 題 BDEFK 。

開局看似順利,不過我們都明白:真真的比拼還沒有開始。

Proxima 卡在了 H 和 C 上, IronGods 通過了 BCDFK 追成 5:5 平,罰時 Proxima 領先。

IronGods 通過了 G ,首次反超 6:5 。

Proxima 經過 rejudge 通過了 H ,出現了 6:6 平,罰時 Proxima 領先。

Proxima 第 10 次提交才通過了 C ,再次獲得題數領先 7 :6 。

如果輸掉了這次 PK ,題 C 則是最大的敗筆。

IronGods 通過了 J ,追成 7:7 平, IronGods 在罰時上領先。

此時的罰時落後就是 Proxima 在 C 題上出錯 9 次的惡果。

Proxima 第 4 次提交才通過 G ,以 8:7 反超,但罰時還是很大。

IronGods 通過了 H ,又追成 8:8 平,利用罰時 IronGods 再次獲得領先。

這已經是第 6 次出現平分了。這時還不到 3 個小時,校內 PK 賽的題目難度並不在 2008 杭州賽區的難度之下, 3 小時的 8:8 的高比分平局是現場比賽中很難看到的。而在高比分平局中罰時也是很重要的,此時 IronGods 佔據明顯的優勢。

Proxima 經過 rejudge 通過了 I ,再次超出 9:8 。

Proxima 通過了 J ,優勢擴大到 10:8 。

記得題 J 的第一次提交開始的返回結果是 “ Other-Contact Staff ” ,看到這個回覆之後 zhuzeyuan 馬上跑到 Judge 室,在被工作人員擋住之後, zhuzeyuan 很奇怪地問道 “ 難道不是你們讓我來 Contact 的嗎? ” ,囧死了。不過很快就 rejudge 成 Yes 了,題 J 的通過也從一定意義上逆轉了罰時的不利, IronGods 如果想翻盤就必須在最後一小時重新上演北京賽區封版通過 3 題一幕。

Proxima 通過了 A ,優勢擴大到 11:8 。

記得最後提交 A 題的時候,我緊張得手都有些發抖了。當時只剩下 25 分鐘, IronGods 還沒有開始寫 A 和 L 兩題,所以在最後的時間裏他們已經不可能通過餘下的 4 題了。 A 題的 Yes 也就成爲了這場 PK 的勝利宣言。

IronGods 最後時刻通過了 I ,最終題數爲 11:9 。

此次校內 PK 的激烈程度決不亞於 2006 年上海賽區,能夠最終贏得這場 PK 使得我們更有自信地站在總決賽的現場。

首先感謝關心我們的同學,記得第一場 PK 當天正在舉行吉隆坡賽區比賽, bbs.pku 上還是出現瞭如此多的帖子爲我們雙方加油。第二場 PK 結束時已經是晚上 11 點,我們手機還不斷收到祝賀短信。

向 IronGods 三位天王致敬,在 PK 過程中只需略微的變化,出現在斯德哥爾摩的就很可能是你們。棋逢對手是我 ACM 生涯的一大幸事,相信你們明年一定能夠做得更好。

我想這是清華第一次使用公開的現場 PK 方式來選拔總決賽隊伍,個人覺得 PK 的方式除了公平之外還有許多優點。首先, PK 方式可以使得各隊伍能夠更從容地選擇和準備不同的分區賽賽區,有效提高學校的總體成績。其次,通過 PK 的過程,可以加強各隊之間的交流,隊伍各方面水平能夠得到全面提高。真是一舉兩得。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧,包括今天一共 10 篇。接下來的重要比賽就是世界總決賽了,縱觀世界總決賽各隊,雖然形勢不容樂觀,但我們一定會拼盡全力。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧。首先是 GCJ2006 的回憶。

Google Code Jam 2006

一波三折:

Google Code Jam 2006 是我第一次到美國參加現場的程序設計比賽。 Google Code Jam 2006 的比賽地點設在了紐約,這次紐約之行之前的簽證出了不小的問題,這裏非常感謝大家對我們的關心,特別感謝吳總( wyy )和魯小石的幫助,使我最終踏上紐約之旅。

從北京到紐約的飛行時間是 13 個半小時,由於是第一次做超過 8 小時的飛機,沒有什麼必要的經驗和準備,路途非常疲勞。一到賓館就睡了,結果由於手機鈴聲的時間使用的是東方時間,差了 12 個小時,一覺把所有事情連晚飯一起都睡過了,隨便吃點東西就繼續睡了。之後的所有現場比賽我都養成了提前睡覺的習慣,以保證充足的體力。

比賽過程:

比賽時精神狀態還算可以,但是分配了比賽房間之後發現自己和 tomek 分在一個房間,真是很不爽;在和旁邊的 zhuzeyuan 抱怨的時候,發現他和 Petr 一個房間,彼此彼此吧。

下面就是比賽過程了,總體來說比賽過程比想象的艱苦,不過其實在 System Test 之前的結果還是很滿意的,先簡單描述一下 3 道題目吧。

250 分的題目是一道平面極值問題,給定 n 個點,求一條直線,使得 n 個點到這條直線的 y 方向截距總和最小。我回憶起金凱在 2003 年集訓隊論文中報告中講到的很類似的一道題目,記得一個重要結論是這條直線一定經過兩個點,雖然題目有些不同,但是很快得到了相同的重要性質:這條直線一定經過兩個點。這樣很容易得到一個 O(n3) 的算法。

500 分的題目是一道反 Hash 函數問題,給定一個 Hash 函數和 x ,求一個最小的非負數 y 使得 H[[yes]]=x 。估計了一下,單向搜索需要 26^8 ,於是我改用雙向搜索,這樣就變成了 26^4 。但是實現過程比想象的複雜很多,提交了後只有 280 左右了。其實,這題有更簡單的數學方法, tomek 的程序有 450+ 。

1000 分的題目是涉及卷積函數和計算反函數的問題,通過轉化變成線性方程求解問題。當時受到現場氣氛的影響有些緊張,浪費了不少時間,提交之後 550 分左右。其實,當時一些原理問題都沒有想清楚,不過後來和 Ying (王穎)經過討論驗證都是正確的。

Coding 結束之前 Petr , tomek , Ying 和 andrewzta 都提交了 3 題,其中 Petr 領先得比較多,我和其餘 3 人差距 50 分以內。

Challenge 階段開始之後,我由於 500 分題自己使用的是雙向搜索的算法,沒有注意到有些單向的搜索加模線性方程的方法其實是正確,在 10 分鐘以內 cha 錯了 2 次。落後於上述的 4 個人,排在第五。

但是下面的 5 分鐘發生了戲劇性的一幕,首先是 Petr 的 250 被 cha 了,接着 Ying 的 250 也被 cha 了,這樣我面臨這樣一個情況: tomek 領先我 100+ 分, andrewzta 領先我 30+ 分,由於我和 tomek 處在一個房間,所以我做出了一個大膽的決定,就是 challenge tomek 的 1000 分題,我隨機生成了一個隨機大數據,在最後時刻提交了這個 challenge ,系統返回了一個令人窒息的結果: successfully challenge 。憑藉這 50 分我一舉超過了 tomek 和 andrewzta ,在 System Test 之前佔據了榜首的位置。

戲劇性的結果:

我很有幸能夠在第一次參加現場比賽時,就能夠和冠軍這麼接近,如果 System Test 能夠全部 Pass 的話,這可以認爲是一場完美的比賽。

可是,整個故事就好像是被刻意設計的一樣, System Test 之後的結果使我目瞪口呆:首先是 250 分的題目,我由於有一個地方沒有及時使用 double ,而造成整數越界;然後, 1000 分的題目簡直是悲劇的最高境界,我在高斯消元的時候沒有及時把一個重要變量暫存,導致影響了結果,沒有想到竟然躲過了那麼多大數據,但是不能通過 System Test 。最後排在 50 名左右。這兩個錯誤至今刻骨銘心。

最終 Petr 獲得冠軍, Ying 亞軍, andrewzta 由於 500 掛了排在第 3 。

11 月的紐約有些冷,我隨大隊人馬一同去了一趟帝國大廈,景色很迷人。第二天休息一下後與幾個中國選手打了一會 “ 找朋友 ” ,第一次美國之行就結束了。

總結:

比賽結果雖然不是很理想,但是對於第一次參加世界比賽的我還算可以接受。也算是爲今後的比賽留下一些教訓吧。

在帝國大廈上見識了大家的拍攝功底,我由於技術差沒有拍到任何合適的照片。

在比賽過程中,首次見識了 liympanda 的大將風度,和 panda 在一起總是笑口常開,他無論遇到什麼情況都無所畏懼,這一點我一直在努力學習,不過一直做的不好。但是 panda 打牌的時候就不一樣了,總是喜歡偷看別人的牌,還炫耀自己會說廣東話,被 Ying 和 rocking 兩位廣東選手狠狠鄙視了一番。

Petr 加上之前的 TCO 和之後的 TCCC ,拿到了 2006 年的大滿貫,可以算是歷史性的突破吧。 Tomek 有些可惜,比完了還問我怎麼 cha 他 1000 分的,呵呵。

其實這次比賽 Ying 挺可惜的,其實 Petr 的發揮並不很好,如果 Ying 運氣再好一些的話,歷史從那時就要重寫了。不過 Ying 還是體現了他超強的數學功底,讓人佩服。另外,來自復旦的同省隊友 LemonTree 也獲得了好成績。

這好像是自己最後一次和 xreborner 同場競技了(由於之後 xreborner 退役了很長時間,忘記 GCJ2008 我們又見面了,謝謝 Savior 的提醒),感謝您在我高中時期教授了我許多編程技巧,我一直沿用至今。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧。昨天是 GCJ2006 的回憶,今天時間上更早一些吧,我現在還清晰記得 3 年前,我剛剛參加 ACM 時參加北京賽區 2005 和杭州賽區 2005 的情況。

2005 年 ACM-ICPC —— 酸甜苦辣

我進入清華大學開始本科學習的時間是 2004 年 8 月,在進入清華大學的第一年裏,由於基礎課學習比較緊張,再加上計算機系不允許大一學生自帶電腦,我沒有參加 2004 年的 ACM 比賽。不過在大一一年中沒有停止這方面的練習,對 ACM 還是熱情高漲。

大概在 2005 年 7 月底,與同班同學 shell (貝小輝)和 superzn (張寧)一起決定組隊參加 ACM 比賽。對於隊名沒有太多的想法,就隨便取了一個字典序靠前一點的 bomber 。隨後進行的幾場訓練中,我的編程狀態一直保持得很好,訓練比賽的主要方式都是:我主寫程序, shell 和 superzn 負責翻譯題目,思考算法和測試。這種組隊模式一直沿用到我們後面的所有比賽中。

2005 年底,我們報名參加了 2005 年的北京賽區和杭州賽區的比賽。順利通過了預賽進入了現場決賽。記得當時北京賽區預賽的時候,我和 superzn 一起在參加百度之星程序設計大賽, shell 依靠一人之力過了 6 題,最後以第二名的資格參加北京賽區現場比賽。

北京賽區:

2005 年的北京賽區地點設在隔壁的北京大學,由於交通非常方便,我們沒有和大部分選手住在一起,不過也沒有參加 Java-Challenge 和晚上的表演。

練習賽之前,說到比賽位置抽籤,本身意義不是很大,可是鄔老師神奇的 RP 把兩隻清華的隊伍抽在一起,結果練習賽進行了一半,另一隻清華的隊伍 THU1 (隊員是:吳景嶽,慄師和金凱,好像後來隊名改成了 DreamCatcher ,不是很確定)被要求換到一個比較遠的地方,理由是有些學校覺得這樣不合理。後來很多賽區也出現過隊伍座位在一起的情況,鄔老師的 RP 果然不是蓋的。

記得練習賽時和復旦的 LemonTree (盛城)一起在場地裏閒逛,結果果然不到 10 分鐘就被要求回座位了。還有當時比賽場地是一個體育館,有些隊伍把氣球放飛之後氣球就飄在天花板下了,總裁判李文新老師還威脅我們說,如果明天正式比賽把氣球放飛,就不算通過相應的題目,除非有辦法把氣球取下來。

然後就是比賽的過程了,下面有底紋的文字是我找到的當時留下的比賽總結:

E :快速排序。 5 分鐘 1Y 。

我想 5 分鐘的時間可以爭取這幾年 ACM 國內賽區的最快出題記錄了吧。

G :二分答案 + 最小生成樹。 25 分鐘 1Y 。

這題就是經典的最優比例生成樹問題,我們一致認爲這題比較簡單。不過後來被李文新老師批評了,說法是誤導其他的隊伍。不過說到最優比例生成樹問題, TCO2006 的時候 fwj 和 tomek 竟然都沒有見過這道題目,這題可是源於 POI 呀。我想我們認爲這道題目簡單的主要原因是我們都在冬令營上見過這到題目,如果第一次看見,想出算法可能確實需要一些時間。在這裏向被我們影響的隊伍的道歉,最終 G 提交了 200 多次,但是隻有 8 個隊伍 AC 。

C :二分圖最大匹配。 42 分鐘 1Y

題目要求計算一張圖的最小覆蓋集,可能唯一的 tricky 是發現圖是二分圖。

D :遇到了一定的困難,發現 A 很簡單,於是先放一下

D 是一道比較綜合的題目,設計一些簡單的計算幾何和字符串處理的知識。

A :簡單的幾何問題,出現了一個低級錯誤,提交了 3 次均爲 WA 。

A 是北京賽區最簡單的題目,我的程序裏犯了一個很低級的錯誤,可能也是經驗不足造成的吧。

D :重新寫,但是沒有考慮一種情況, WA 了 1 次。

87 分鐘,復旦的 Abuacus 過了 4 題佔據了 Rank1 。由於隊伍模式的原因,我們在還有很多簡單題目的情況下卡住了長達 30 分鐘。

A : shell 突然發現了 A 程序中的低級錯誤, 105 分鐘 AC ,重新奪回 Rank1 。

這是很重要的一步,現在想來如果沒有這個發現,後果可能不堪設想。

B :二分答案 +2SAT 。 129 分鐘 AC 。

B 是一道明顯的 2SAT 問題,由於題目比較長,我們沒有很早發現這道簡單題。

D :發現了 D 的沒有考慮的情況, 140 分鐘 AC 。

看了一個 board ,那時 Abuacus , Eccentric 都只有 4 題,能夠在第一次參加正式比賽就做到 6-4 的領先,當時心情很激動,不過由於缺少經驗,也影響了接下來的發揮。其實,現在回想起來,這次比賽其實是一個很好的 AK 的機會。

F : DP 。程序比較複雜, WA 了 4 次。

F 是一道比較複雜的動態規劃的題目,其實 WA 的原因是一個應該用 int64 的地方,我們使用了 int ,這個地方的確很難發現。

H : F 一時無法 AC ,只好轉功 H 。 H 就是普通的模擬題。開始沒有考慮坦克和炮彈可能在 1/3 秒相遇, WA 了 1 次。

比賽還有一個小時,封板。

H : shell 發現了坦克和炮彈可能在 1/3 秒相遇的情況, 250 分鐘左右 AC 。

對於我們這種組隊模式,當主寫程序的選手狀態不好的時候,很容易出現連續卡題的情況,這種情況的出現很不利於水平的正常發揮。在北京賽區的比賽中,我們很有幸沒有出現連續卡處的情況。

記得,當時北京賽區的 Judge 的半自動的,就是說如果結果是 AC ,速度就會非常快,否則由於人的介入,不能 AC 的提交往往需要等一段時間。我們第 2 次提交 H 之後,沒有得到很快的回覆,以爲已經 WA 了,於是我和 superzn 繼續測試一些數據。但此時,突然有一個 mm 從左邊走過來插氣球,這個氣球也成爲了全場唯一的藍色氣球,這個意外之喜最後成就了第一個分區賽冠軍。

F :下面就是痛苦地提交 F ,一直戰鬥到最後一刻, WA 了 14 次,留下了北京賽區最大的遺憾。

在最後時刻我們似乎發現了那個 int64 的錯誤,不過當時思路已經比較混亂了,沒能改對。 F 的問題也導致沒有時間寫 I ,當時如果直接重寫後者換 superzn 來寫 F ,完全可以在比賽結束前 AC 。

比賽的大致過程如上所述,那個神奇的氣球,我現在仍然記憶猶新。最終有 4 個隊伍攻破 7 題, Abacus 的組成應該是盛城, timegreen 和 suzhan 吧, Eccentric 中我只記得辛韜, ZSU_Panku 中我記得 Savior (陳實)。上述的老朋友之後見面的機會就很少了,分區比賽也成爲了我好需要老同學重要的交流機會了。

我 ACRush 的 ID 估計就是那時開始使用的吧,轉眼就已經 3 年多了。

比賽前後還記得經常與復旦大學的吳永輝老師聊天,在那之後的每次比賽我都能見到他年輕的身影。

現在回想起北京的分區賽,很有幸能夠在第一次參加 ACM 正式比賽就獲得分區比賽的冠軍。我想是由於現場氣氛對許多隊伍都有不小的影響吧,當時許多隊伍都卡在幾道比較繁瑣的題目上了,題目的算法性都不是很強。我大概從那時纔剛剛接觸 TopCoder ,如果能夠早一些,相信會更適應這樣的比賽。

杭州賽區:

2005 年的 ACM 杭州賽區比賽在浙江大學舉行,杭州賽區的時間就在北京賽區結束後一週,最初選擇杭州賽區的原因很飄逸:我自己家在杭州。實際上也差不多,我隨隊伍(當時 THU 派了 3 只隊伍參加杭州賽區的比賽,除了我們隊之外, b142857 (侯啓明), zhy (周源), ysy (楊思雨)組隊,另外一隻由汪汀,王俊和黃源河組成)一同抵達杭州車站之後就馬上回家休息了,直到比賽前才趕回。在北京到杭州賽區之間的一週中,我的狀態就在不斷下滑,在家中完全失去了比賽的氣氛,回到賽場再也找不到感覺了。一場悲劇即將上演。我們先看看比賽過程吧,下面有底紋的文字是我找到的當時留下的比賽總結:

G :初看很簡單,但是調試了 30 分鐘沒有結果。

G 是一道數學問題,其實《具體數學》書上有明確的公式,不過我們使用的遞推方法應該也可以得到正確的結果。程序中犯了一些低級的錯誤,由於實在不在狀態,調試了 30 分鐘還沒有找到錯誤。這裏還暴露了一個組隊模式的問題,在後來的組隊模式中,如果像這樣沒有想清楚算法的題目隊友是一定不允許我去寫的。

A :模擬。 41 分鐘 AC ,當時肯定沒有想到這是唯一一道 1Y 的題目。

A 是一道模擬題, 1Y 的時候已經很晚了,排名也很靠後。

C :圖論。但是由於堆棧逸出 RTE 了 5 次,浪費了大量的時間。

C 的問題關於樹中祖先關心的判定,題目很簡單,實現的方法也很容易,就是通過一遍 DFS 來計算。但是我們忽視了一個從來沒有遇到過的問題:堆棧溢出。而且,堆棧在本地機器上運行過程中, Eclipse 提供了 8MB 左右的堆棧,所以沒有溢出,但是在提交之後的環境下運行就溢出了。而且每次 RTE 之後,我們一直在嘗試修改數組的大小,一直沒有找到根本原因。調試 C 的同時,我也嘗試修改 G ,結果 G 也錯了 8 次之多,並且始終都是 WA 。

I : shell 在我鬱悶地調試 C 和 G 中 AC 了,之前 WA 了一次。

I 是動態規劃問題, WA 一次可能是忽視了一些邊界情況。

D :網絡流,沒有想到先貪心進行優化。 TLE 了 5 次最終沒有通過。

D 就是計算最小割,我們事先準備了先流推進算法,不過根據這道題目的模型,先流推進算法遇到最壞情況:二分圖。由於當時 dinic 還不是很流行,我們 TLE 了 5 次還沒有通過。

鬱悶地調試 D 和 G 。

E,B :都嘗試過,但是都出現了不明的問題。

在隨後的時間裏,不斷調試 D 和 G ,但是始終不能 AC 。之後又嘗試 E 和 B , E 通過分段的方法可以處理, B 是數學題目。正常的話 E 和 B 並不是很困難的題目,但是當時已經非常混亂,連樣例都沒有通過。

最終我們只過了 3 題,排在 21 名,經歷了我參加 ACM 以來最慘痛的失敗。這次失敗主要歸過與我狀態太差,基本上什麼題目都不能順利通過。當然題目的選擇也有很大的問題: G 確實不是難題,但是由於未知的原因始終不能通過,後來我把紙上的程序敲在 ZJU 上就 AC 了,至於現場爲什麼不能 AC 我現在還是不能明白。如果說第一題的選擇直接影響了我們的信心,那麼 D 的堆棧溢出則完全打亂了我們的節奏。對於我們的組隊模式,卡出 2 題已經超出了極限,我們不可能再嘗試其他題目。

Abacus 也來到了杭州,他們前期體現了強勁的先期優勢,在 2 小時就達到了 6 題; b142857 (侯啓明), zhy (周源), ysy (楊思雨)的隊伍表現得相當神勇,在最後一小時超越了 Abacus ,奪得了冠軍。

杭州賽區的失敗至今仍是心中痛苦的回憶,不過這個教訓也是對我今後的學習生活的一種警示。

總結:

2005 年是我第一年參加 ACM-ICPC 的比賽,兩場 ACM 分區賽,我們經歷了奪冠的興奮,也經歷了環顧四周等待比賽結束的無奈。 2004 年清華沒有獲得任何分區賽的冠軍, 2005 年清華打了個漂亮的翻身仗,先後在成都,北京和杭州奪得冠軍,而且是三支不同的隊伍。

兩個賽區的 G 都是有傳奇色彩的題目。北京賽區中,我們 25 分鐘 1Y 了 G ,導致許多隊伍跟風失敗,最終達到了 208 提交 8AC 的低通過率。但是,杭州賽區中, G 從比賽一開始就佔用了我們大量的時間,直到最後都沒有通過,估計至少浪費了兩個小時左右。真所謂成也在 G ,敗也在 G 。

北京賽區後, POJ 的論壇上傳聞說我曾經說過 “ 起身去廁所,不許碰鍵盤。。。 ” ,很敬仰那些同學搞笑和扯淡的功底,我們雖然定下了以我主寫程序的組隊模式,但是也非常重視配合和每個人在隊伍中的重要作用。

當時清華沒有組織校內 PK 選拔,選擇了成都賽區的冠軍隊 THU1 參加全球總決賽,當時總決賽隊伍是以參考第二賽區的成績決定的,現在回想起來也是很合理的。由於最終我們未能得到機會參加全球總決賽,接下來幾個月我們情緒低落, bomber 從那時也就宣佈解散了吧。

2005 年的比賽過程中,我見到了許許多多的老朋友。用吳永輝老師的話, ACM 競賽可以看作一些老朋友一起進行的一場智力遊戲。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧。回顧了 GCJ2006 和 2005 年的 ACM 之後,轉向 TopCoder 的比賽吧。我參加的最早的 TopCoder 賽事是 TCCC2006 。

TCCC2006 —— 死亡之組

TopCoder Collegiate Challenge( 簡稱 TCCC) 是 TopCoder 一般在秋季舉行的面向全世界在校學生的程序設計大賽, 2006 年的 TCCC 在聖地亞哥舉行。從北京到舊金山的飛行只需要 11 個小時左右,所以不至於那麼疲勞。路上一切都很順利,很感謝 OpenGL 的提醒,對於超過 8 個小時飛行自帶拖鞋和枕頭對我來說還是很重要的。

TCCC2006 使用的標準的 TopCoder 現場比賽形式,比賽有 48 名選手參加,首先 48 名選手被分爲 16 個人一組,每組分別進行半決賽,前 2 名直接晉級決賽, 3-6 名晉級 wildcard 比賽, wildcard 比賽 12 人中的前兩名填補決賽的最後 2 個名額,決賽由 8 個選手參加。 TopCoder 現場比賽中很重要的一個創新是:每名比賽選手在觀衆席前都有一個同步的顯示器,這樣觀衆可以看到選手任何時刻做的事情,極大增強了互動性。

TCCC2006 的 Room 1 和後面的 Final Round 都可謂是死亡之組。現在就回憶一下這兩場激烈的比賽吧。

Room 1 :

至於 3 個房間的分配, TopCoder 按照註冊截止時選手的 Rating 分佈蛇形分配。但是 TCCC2006 的房間實力分佈極不平衡,我與上屆冠軍 tomek ,著名選手 reid , Egor , halyavin 還有 Rating 不高但是實力極強的 Ying 和 ardiankp 同被分到了 Room 1 ,賽前 Room 1 成爲公認的死亡之組。

在聖地亞哥,我和師兄 Macsy (張一飛)同一個房間,很感謝師兄的關心,我那幾天休息的都很好。要知道如果同房的人有 10 小時左右的時差的話,一人必須很小心才能保證不影響另一人的休息。

Room 1 在我抵達美國的第二天早上進行,選手允許提前 30 分鐘準備一些必要代碼。不過現在大家都比較喜歡學習 Petr 那樣一行代碼都不打。下面就是比賽的過程:

250 分題目是:給定 n(n<=50) 個整數 AI 和一個閾值 d ,計算 n 個整數所有排列 PI 中滿足 |API-API+1|<=d 的排列中,所有不同可能 AP1 的個數。這題最標準的方法是動態規劃,基本思想是把 n 個整數排序之後,計算兩條相鄰元素不超過 d 的序列。我使用了一種更精巧的算法,把 n 個整數排序之後,對於 AI ,如果 AI 可能作爲排列的第一個元素,那麼 AI 必定在某一個方向(大小)連續而在另一個方向每間隔兩個元素相連。這個算法比較容易實現,但是正確性證明比較難,甚至讓人第一感覺是錯的。我寫完程序測試了所有樣例都正確就提交了, 243 分。提交之後我又測試了許多數據,並在紙上嘗試證明正確性。

賽後,我看了網絡上的討論記錄。在我提交 250 分題之後,立刻遭到了 misof 的懷疑,他認爲我的算法有問題。據 Macsy 學長的回憶, OpenGL 在我屏幕前看我寫完程序,也認爲我的算法是錯的,不過後來他們討論之後發現沒有反例。

關掉 250 分題目之後,我剛剛意識到 Room 1 的 3 題分數不是 250-500-1000 ,而是 250-600-900 。現在看來,對於 250 比較順利的情況,應該先做 500 ,若 250 不順利或者想出奇制勝的話,可以先開 1000 分。當時沒有什麼經驗,我認爲 900 比 600 應該簡單一些,於是就打開了 900 。

900 分題目是:給定一張 n(n<=10) 個點的帶權有向完全圖(也就是 n2 個實數)和一個衰減係數 p ,求一條經過 d(d<=10) 條邊路徑(不需要保證簡單路徑),要求這條路徑的指數衰減長度(指數衰減是指第 i 段的長度乘以 pi-1 然後求和)最接近 1000 。這題如果使用窮舉法,就需要 1010 左右的計算量,在 TopCoder 的測試機上也不能通過,由於路徑長度很容易超過 1000 ,所以很難找到多項式時間的動態規劃。我馬上有了一個想法 —— 雙向搜索。對於長度爲 d 的路徑,其實可以看作從某一個點 p 出發的一條反向的長度 [d/2] 的路徑和一條正向的 d-[d/2] 的路徑,對於固定的節點 v 來說,這種兩個方向的路徑都不超過 n[d/2] ,這樣只要枚舉一個方向的路徑然後二分查找另一個方向即可。複雜度是 O(dn2+[d/2]) 。

現場比賽調試環境不是很好,我花了不少時間調試以發現程序中的錯誤。提交之後 690 多分,還不到 700 。不過對於 900 分的題目在那種壓力下還可以接受。提交之後我花了 15 分鐘左右測試,沒有發現錯誤。於是就準備做 600 了。

600 分題目是:一道經典的數學題,給定一些盤子疊放的規則,計算頂層盤子的最大可能大小。其實算法不是很難,只要二分頂層盤子的大小,然後依次貪心計算來判斷底層是否能夠滿足即可。只是貪心的時候要考慮兩種情況,一時想不清楚。我當時已經感覺很疲勞,思路不是很清楚,最後 40 分鐘時間也沒能調試通過。這題過於瑣碎, Room 1 中最終沒有選手通過 600 分題,並且成就了一個刺激的 Challenge 階段。

Coding 階段我和 tomek 採用了截然不同的策略,我跳過 600 直攻 900 ,而 tomek 在 600 中掙扎了很長時間才放棄。 Coding 階段結束時,有 4 名選手提交了 3 題。我依靠速度優勢領先同樣提交 250 和 900 的 tomek 35 分左右。

Challenge 階段開始時,我盲 cha ( blind challenge )了一個最後時刻提交的 900 分程序,但是由於我選擇的數據實在太弱,失去了 25 分。這樣我和後面的 tomek 只相差 10 分左右了,所以我決定只要 tomek 不動,我也不動了。其實,當時 tomek 已經知道自己的 900 是錯的, Challenge 階段他估計已經放棄了。我的 Challenge 階段最終就以 -25 分結束。

之後的 Challenge 就是 Ying (王穎)展現勇氣和智慧的舞臺了。他 Challenge 掉了所有提交的 600 ,憑藉 225 分的加分超過了我,排在榜首。這樣比賽的形式也一目瞭然了, 7 位選手提交了 900 ,我依靠速度優勢領先第四名 reid 超過 100 分。只要我兩道題目能夠 Passed System Test 就足以進入 Final Round 了。

System Test 之前,我和 Ying 討論他 “ 超神 ” 的 Challenge 階段。這是我第一次參加 TopCoder 的現場比賽,發現 System Test 結果顯示是按照 System Test 之前的排名倒序進行的。測試到我時,除了 tomek 的 4 名選手的 900 都過了。顯示我的結果時,兩個綠框閃爍了很久終於顯示出了兩個大大的鉤,我終於可以歡呼慶祝勝利了。我前面的 Ying 也兩題全過了。這樣我們兩位中國選手得以在死亡之組攜手出現,這場比賽真可謂是中國選手的勝利。 Reid 只能在 Wildcard 賽再作努力, tomek 則被直接淘汰出局了。

Final Round :

接下來的兩天裏,我觀看了 Room2 , Room3 和 Wildcard 的比賽。第 2 天晚上我們參加了 TopCoder 贊助的 Laser Tag 遊戲,我們所有中國人組成了一隊,我的發揮很差,原因是這個遊戲與 CS 不同,選手頭上沒有感光器,而我喜歡遇到人就攻擊頭部,所以狹路相逢多半是我失敗。活動中,我有幸結識了許多 Dev 的神人,當時由於 vividmxx 沒有參加, magicpig 和 PE 的競爭很激烈,最終 PE 獲得了 “ 浙江大學建校 100 年來第一個 TCCC 冠軍 ” 。記得賽後我 uncle 來到現場,我 uncle 是浙江大學本科畢業的, magicpig 見我 uncle 第一句話就是 “ 浙江大學建校有 100 年曆史了吧? ” 汗死了。另外 zjq 也獲得了 Design 的亞軍。

第三天中午 Championship Round 開始了。決賽時,場地裏安裝了很多攝像頭,可以說我們的任何舉動都在嚴密監視下了。這回我提前確認了題目分數是標準的 250-500-1000 的分佈。參加決賽的選手除我之外有: andrewzta , ardiankp , bmerry , Eryx , mathijs , Petr 和 Ying 。面對決賽選手的實力,我已經沒有意義定一個類似於 “ 保幾爭幾 ” 的目標了,努力發揮自己的水平是最應該做的。下面就是比賽的過程了:

250 分題目是:給定 n 個正三角形,每個頂點都有數字,選出 6 個三角形拼成一個正六邊形,要求相鄰的數字必須相同。三角形允許旋轉,計算能夠得到多少個本質不同的正六邊形。題目很長,我仔細讀了兩遍纔開始寫,算法很清楚,就是枚舉六邊形中心和四周的 7 個數字,然後判斷是否有足夠的三角形。在判斷本質不同的時候犯了一個錯誤,調試了幾分鐘,提交之後只有 215 分了,看了一下排名, Petr 有 232 分之高,其他選手都還沒有提交。測試了幾分鐘發現程序的運行時間不是很穩健,很容易到達 0.8 秒左右,測試了 15 分鐘之多才逐漸放心下來,因爲基本上所有數據都 0.8 秒左右。賽後 Macsy 告訴我,我的程序速度瓶頸是在 set 的判斷,所以時間比較穩定,不會超時。我當時的猶豫和沒有經驗浪費了至少 20 分鐘的時間。

按照賽前的計劃,我這時應該打開 1000 的題目的,但是由於自己對 250 沒有信心,而且求穩思想比較重,我先打開了 500 分的題目。現在看來,開 500 分的題目並不算錯誤,其實在打開 500 分題目的時候,與 Petr 的差距不是很大。

500 分題目是:給定一個機器人的移動命令序列,要求計算結束時機器人的位置。由於移動序列中允許 () 這樣的重複操作,直接模擬是超時的。這類題目的標準算法是利用矩陣乘法,由於之前對於此類題目沒有經驗,沒有準備好就開始寫了,導致矩陣處理失敗。我果斷放棄了調試,換用一種記錄中間結果的搜索方法,寫完的時候已經只有 280 分了。更重要的是我已經沒有時間進攻 1000 分了。提交之後排在第 3 ,前面是 Petr 和 Eryx 。

1000 分題目是:給出一個排隊取菜的模型,計算一個等待時間的排隊序列。而且對於多種答案的情況,要求計算字典序最小的序列。題目其實不是很複雜,集合動態規劃就可以解決,不過模擬取菜過程時需要非常注意細節。 Petr 提交了一個 660 分左右的程序, Ying 則在最後一分鐘提交了 400+ 分,排在第 2 。

Challenge 階段顯得很枯燥無味,前兩天大發神威的 Ying ( +225 )和 Petr ( +300 )都沒有嘗試 Challenge ,整個 Challenge 階段沒有任何一個 Successful Challenge 。

System Test 結果出來了,在 bmerry , ardiankp 和 andrewzta 都只通過一題的結果出來之後,排在我後面的 mathijs 兩題都 Pass ,隨後我的 250 和 500 也都 Pass 了。但是,排名在我之前的 Eryx 和 Ying 的 500 分和 1000 分都 Failed System Test 了,我瞬間提升到了第二名的位置。不過雖然 Petr 的 1000 分掛了,但是他依舊憑藉 250 和 500 的速度獲得了冠軍。

在這裏說一下 1000 分的真實情況吧,因爲這些時間來對於 TCCC2006 Final Round 的 1000 分題目有很多不同的說法。比賽結果中顯示沒有選手通過 1000 分題,如果仔細分析測試結果, Petr 的程序由於超時出錯,而 Ying 的程序由於一個地方沒有清 0 而導致錯誤,確實很可惜。因爲如果 Ying 的 1000 能夠 Pass 的話,他將是 TCCC 的冠軍。不過 Ying 的算法犯了與造成 Petr 超時一樣的錯誤,他們的動態規劃程序比標準方法多出一個 n 倍的時間,我曾經成功生成了一個用例,可以讓 Ying 和 Petr 的程序都超時,這個例子已經得到了 Ying 的認可。需要指出的是 TCCC2006 是 TopCoder 的測試機的速度還是很慢的,兩個程序如果在現在的機子上運行可能只需要 1 秒左右了。

比賽之後和 uncle 到 downtown 遊玩了一下,參加完頒獎晚會,第二天就回國了。

總結:

TCCC2006 是我第一次參加 TopCoder 的現場比賽,很有幸能夠在這麼多的第一次中就進入決賽並且獲得第 2 名的成績。很感謝同參加比賽的同學 Macsy , OpenGL , Ying 還有 PMH 的關心和幫助,你們在我比賽時全程在場邊,讓我感覺很溫暖。

另外,我還有幸認識了 visualage ,現在他已經是 arena 的負責人了吧。記得他和 OpenGL 在 Room 1 的 Challenge 階段通過大聲叫中文(在國外,這是最好的密碼)告訴我 tomek 的 900 是錯的,可惜我沒有聽見。

TCCC2006 對於中國來說是不小的收穫,中國選手佔領了 Dev 比賽, PE 獲得 “ 浙江大學建校 100 年來第一個 TCCC 冠軍 ” , magicpig 和 zjq 分獲 Dev 和 Design 的亞軍,也就是說中國包攬了所有亞軍。在比賽之餘,我很高興認識了衆多 TopCoder 的朋友。

Petr 在決賽中表現了非常良好的狀態, TCCC 的奪冠標誌着 Petr 收穫了 2006 年的大滿貫。 Ying 也採用了很合理的策略,只可惜他的賭博由於運氣差一些惜敗。我採用了比較保守的策略,在所有決賽選手中排名第 2 ,這也是我在 TopCoder 的現場賽事中的最高名次了。

TCCC2006 我很感謝家人的關心,父母凌晨很早起牀查看我的比賽結果,而 uncle 還特地趕來現場爲我加油。這幾年的 TopCoder 現場比賽的贊助商列表裏都能找到 American Online(AOL) 的身影, TCCC2006 是 AOL 唯一一次進行了 3 個小時左右的全程直播,父母和 uncle 都在網絡上觀看了現場的影像直播。

TCCC2006 我神奇地保持了 100% 的正確率,我個人認爲 TopCoder 現場比賽對正確率提出了更高的要求,我們不必太在意 Coding 階段的那些高分,只要自己的程序是正確的,就是成功的。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧。回顧 GCJ2006 , ACM2005 , TCCC2006 和 ACM2006 之後,今天簡要回顧一下國內個人賽場吧。

國內個人賽場 —— 百度之星

國內個人賽場中最重要的比賽要數每年一度的百度程序設計大賽,到今年爲止已經舉辦了 4 屆,每一屆我都全身心地參加了比賽的全過程,百度程序設計大賽是中國舉辦的規模最大的公開程序設計比賽,其參加人數比許多世界範圍的程序設計大賽的人數還要多得多。另外在 2006 年初, Google Beijing 舉行了 Google Code Jam China 的比賽,剛剛開始參加 TopCoder 的我也加入了這次 GCJC 之旅。

第一屆 baidu 程序設計大賽:

最早的國內個人程序設計比賽要回憶到 2005 年 9 月開始的第一屆百度程序設計大賽了,源於宿舍走廊中的海報,我以嘗試的心態報名參加了第一屆百度程序設計大賽。每一屆百度程序設計大賽都由初賽,複賽和現場決賽組成。

第一屆百度程序設計大賽中,印象最深的複賽題目就是那道規模巨大的最小樹形圖問題了, 100000 的數據規模嚇退了不少選手,我鼓足勇氣提交了一個理論上能夠運行的程序,順利通過了複賽進入決賽。最小樹形圖算法在大多圖論書上就接在最小生成樹算法後面,但是其程序量遠比最小生成樹大,而且用途沒有最小生成樹廣泛,在大多數競賽中很少出現。我最早接觸最小樹形圖算法是在 2003 年 4 月,當時正在復旦大學訓練,記得關於這個問題和 xreborner 討論了很長時間才得以證明算法的正確性並實現出高效的程序。

現場決賽於 2005 年 10 月底在北京舉行,由於當年比賽的知名度不高,時間上還和 GCJ 衝突,沒有太多的頂尖高手參加。清華大學除我之外只有 superzn (張寧,我們留 shell 一個人參加 ACM 北京賽區預賽 L ),當時 OpenGL 還是以高中生身份參加的,還有復旦大學的 xreborner 和 young (李陽);中山大學的 magicpig , Savior 和張子臻(不好意思,我不記得您的 ID 了,好像杭州 2008 的時候我們還說起此事)。我一直認爲,現場比賽過程的一個重要的意義在於提供了一個老朋友重逢和結實新朋友的機會,選手之間的交流是比賽中最重要的組成部分之一,我很有幸能夠在這些比賽中認識了衆多牛人。

稍微回顧一下決賽的題目吧:決賽的題目是經典的 8 數碼問題,給定初始狀態和結束狀態,計算最短需要的轉移步數。對於分數相同的情況,按照程序的運行速度排名。比較容易想到的方法有:

(1) 單向 BFS :最壞情況需要 1s 左右。

(2) 雙向 BFS :如果先判斷無解情況,這是 xreborner 使用的方法,平均情況大概 0.002 秒左右。

(3) A* 或者 IDA* :先判斷無解情況,然後通過距離啓發函數搜索。平均情況大概 0.002 秒左右。我當時使用了 A* 的方法,但許多地方的實現不是很合理。

(4) 常量表,這是最有挑戰的方法,因爲決賽的提交量限制在 64K 以內。

現場比賽中, (2) 和 (3) 的使用人數比較多,速度相差無幾,選手之間比拼的是各種細節和常數的處理。後來,我想出了一種速度非常快的方法:

首先使用 A* 加上 “ 卡節點 ” 技術,就是限制 A* 算法搜索過程中每層的節點個數上限,這種算法擴展節點個數在 100 左右。然後,由於上述算法的正確性不能保證,把所有反例打成常量,程序大概 50K 左右。很容易發現,這個程序的速度遠比比賽過程中所有程序的速度都快得多。

最終我的程序以總時間 0.022 秒獲得冠軍, xreborner 和 Savior 以 0.026 分並列第二名。 xreborner 的程序很可惜,如果加入了無解判斷,速度應該比我程序塊, superzn 就更可惜了, superzn 的飄逸程序其實只有 0.020 秒,但是有一個數據錯了。

記得頒獎之後,主持人邀請獲獎選手發言,選手可以通過向前走一步選擇優先發言。這時,我突然感覺大家把目光都聚焦到了我身上,向右一看,由於我站在最左邊沒有注意到右邊的情況,可誰知其他選手都後退了一步,把我留在了看似向前一步的位置。

第二屆 Astar-baidu 程序設計大賽:

第二屆百度程序設計大賽沒有等到 10 月,而是在 2006 年 6 月就拉開序幕。沒有想到的是,第二屆百度程序設計大賽竟然以我在一年前比賽中使用的 A* 算法的名字命名,感到非常榮幸。

記得複賽的題目非常正式,印象最深的要數 xreborner 招牌式的 Zuma ,我推了兩個小時公式纔得到了正確的動態規劃方程,實現之後還由於 TLE 只有 30 分 (100 滿分 ) 。還有 Ying 出的無向圖最小割問題,我用網絡流算法又超時了。不過最後一題,我的程序竟然比 xreborner 優化過的標程還快,真是不容易呀。清華的舍友 RealPlayer 在複賽中表現很興奮,可惜由於一個很小的錯誤沒能進入決賽。

參加第二次百度決賽的選手中有許多熟悉的面孔,清華的同學包括 shell , OpenGL , lympanda 還有 Macsy 。復旦大學也來了很多選手,其中除了 LemonTree 和 Topkiller (沈毅)之外,還有我剛到復旦時見過的 admin 和 funny 的身影。另外 magicpig 和 flymouse 也參加了,而且 magicpig 和我住一個房間,吃飯時記得他把桌上所有人的 Dev 功底全都鄙視了一遍,可惜 PE 不在場呀。比賽前還看到了 Srbga 的身影,據他說是被邀請一起來玩的,其實稍微用小腦判斷一下就知道一定是參與出題的,有了 Srbga 的加盟,相信決賽題目絕對不會是一年前的風格了。

第二年決賽的題目是:著名的俄羅斯方塊。寫程序玩一個 10 列的標準 2 維俄羅斯方塊遊戲。

Srbga 設計了很有特色的記分方法和評分標準。對於記分方法,特別的地方是消去 1 行後沒有得分,而同時消去 2 , 3 , 4 行的得分分別是 3 , 6 , 10 ,記分方法非常鼓勵一次消去多行。評分標準則更奇怪了,有 50 種不同規模的數據,對於每組數據對所有選手的得分進行排名,前 8 名的選手依次得到 10 , 7 , 6 , 5 , 4 , 3 , 2 , 1 分,也就是說,是存在可能性在測試結束之後分數仍然爲 0 的。

比賽過程中,我花了許多時間來分析這個奇怪的評分標準。

對於這種評分標準,常見的策略有兩大類: (1) 所有數據的成績比較平均 (2) 在一種數據風格中特別突出呢。

根據數據描述, 50 個數據可以分爲 10 種不同的風格。參加比賽的總共有 50 名選手,如果所有分數是完全平均分配的話,分數是 31 分,這個數字意義不大。但如果設想分數的 80% 會分配在前 10 名中(根據當時選手的水平,這個假設還是比較合理的),這樣前 10 名的平均分數是 124 分左右,也就是說如果想擠進前 4 ,至少也要 100 分以上,如果想爭取冠軍估計需要 200 分左右。如果選擇一種策略,使得它只在一種數據風格中特別突出,分數只有可憐的 50 分,而且很可能有許多有同樣想法的選手,所以 (2) 不太可取。

在決定選擇比較平衡的策略 (1) 的之後,需要再考慮一個問題,如果最終目標是 150 分,那麼平均分數只需要 3 分,也就是說每個數據可以允許有 5 名選手超過自己。這些必要的分析幫助我明確了努力的方向,面對這種開放性的題目,多分析題目的特點往往可以達到事半功倍的效果。

還有一個重要環節是調整估價函數,機器學習其實是一個很好的策略,可惜我當時不會。其實當時我做的事情,本質上就是人工模擬機器學習,手工調整了 1 個半小時,眼都花了。而且我犯下了一個致命的錯誤,記得記分方法非常鼓勵一次消去多行,也就是說對於平坦的數據,一次消去 1-3 行的權值應該可能設置爲負數,而我只把他們設成了 0 ,使得程序對於平坦的數據分數不高。 Macsy 就考慮到了這一點,只可惜一個很奇怪的技術問題(在 Linux 和 Windows 下的 CLOCKS_PER_SEC 參數是不一樣大的,想使用卡時策略時千萬不能事先把這個數字取出來設置成 CONST )使得 Macsy 沒能成功。

由於 Macsy 和 LemonTree (同樣的技術問題)的出局,我在許多數據中得到了很高的分數,最後的總分達到了是 255 ,領先了第 2 名有 99 分之多。其實現場的許多選手的程序風格相差並不大,可能我唯一多做的事情就是建立了一個博弈樹,多搜索兩層,這樣比直接貪心的程序看得更遠一些。後來事實也證明了,排名靠前的選手大多都是比較平衡的策略。記得 lympanda 洋洋灑灑寫了 1800 多行程序,在其中一種數據中拿到了滿分 50 分。不過可惜 panda 的程序平衡性稍差,總排名進入了前 10 ,但最終只有三等獎。

第二屆 astar-baidu 程序設計大賽,復旦大學獲得了豐收。記得許多復旦的選手由於考試提前回到學校,頒獎儀式的時候二等獎頒獎一片空場。

比賽的住宿條件可以用無與倫比來形容,很感謝 baidu 的大方與細心。記得第一天晚上還有機會和 Ikki 一起打沙壺球,面對球風完全對立的 Ikki 玩得很開心。

Google Code Jam China 2006

大概是 2005 年末,突然看到了名爲 GCJC 的比賽,而且使用的是 TopCoder 的比賽模式,於是就報名參加了。當時估計只參加過幾場 TopCoder 的比賽,帳號還是藍色的, GCJC 第二輪預選賽由於經驗不足差一點就被淘汰了。好在有驚無險地進入到了北京的現場賽。

GCJC 現場的選手中,我覺得至少認識 80% 吧,清華同學就有 7 人: b142857 , fuwenjie , lympanda , Macsy , zig 還有 hyyylr (李老師),復旦的 LemonTree 和 TopKiller 也都來了,浙大也來了許多 TopCoder 上的元老 xuchuan (徐串), sghao126 。

記得,就在 GCJC 決賽的前一天晚上,我參加了 TopCoder 的 SRM 比賽,第一次踩住了 Petr ,不過也消耗了太多的 RP 。晚上的 SRM 比賽中沒有人過 3 題,第二天早上 lympanda 還把我們統統鄙視了一遍。隨後, b142857 還描述他 Challenge 過程中的囧事,由於 500 分題目的返回結果需要使用 long long 類型,所以 b142857 看到一個人提交的程序計算過程中只使用了 long 就果斷 Challenge 了,結果失敗了兩次之後才發現,那個人用的語言是 Java 。

比賽中 250 分題目,簡單的概率問題。我寫完就交了 224 分,竟然是所有選手中最快的。後面的 500 分,我雖然提交是最快的,不過沒有考慮一種情況。打開 1000 分題目之後網絡就開始很不穩定了,時斷時連, 1000 分題目其實算法很清楚,由於網絡原因提交只有 600 分左右了。

Challenge 階段開始時,我打開了房間中 lympanda 的 500 分程序,發現我們兩人的程序基本過程完全一樣。又打開了一個,也一樣。但是在還沒有反應過來的時候, lympanda 的 500 分程序被 Challenge 了,接着我的 500 分也被 Challenge 了。然後就沒有什麼鬥志了,在無奈中等待比賽結束。

比賽結束之後的午飯過程中,我正好坐在 Google 中國掌門人李開復旁邊。午餐快結束時,李開復問起 2 個月前的百度程序設計大賽,突然,鬼使神差地直接問我百度大賽的冠軍是誰?這可是在 Google 的老巢呀,抖死了。我當時真害怕他聽完回答之後直接把我趕下桌 tongueout 。

好在我的 250 分和 1000 分都 Pass 了,由於 TopKiller 的 1000 分超時了,我獲得了第 3 名。冠軍 xuchuan 和亞軍 b142857 都順利通過了 3 題。

POJ Monthly Contest

大概是從 2004 年 8 月開始, POJ 上開始舉行每月一次的有獎月賽。 2005 年的月賽中,每次都有機會同 xreborner , Ying 等高手切磋技藝。從 2006 年初開始,我已經比較熟悉了比賽的題風,連續獲得了許多次比賽的冠軍,並且保持了良好的個人比賽狀態。

記得 2006 年 4 月底,在 POJ 的郵箱裏突然發現了 hawk 的信,他問我五一長假回家的情況。我告訴 hawk 自己定在週五晚上出發。於是,第二天早上就看到比賽安排中: 2006 年 5 月份月賽安排在了週五晚上,太囧了。

後來, POJ 上直接出現了一系列奇怪的定義,但其實結論就是我不能以正式身份參加月賽了。現在這些定義早已成爲笑料了,但是我不參加月賽之後,仍然有 ahyangyi 這樣的選手奪走了絕大多數的冠軍。

後兩屆 baidu 程序設計大賽:

從第二屆開始,我們習慣了在每年 6 月等待 astar-baidu 的開賽。 2007 年最出乎意料的就要數 CS 這個決賽題目了,我在關鍵的買槍環節犯了重要錯誤,太迷戀 AK47 了。祝賀師兄 lympanda , Macsy 還有 shell ,不愧是真金不怕火煉。

第四屆百度大賽我參與了預賽和複賽的命題工作,但是沒有參與決賽的命題。決賽題目是一道關於直升機的題目,印象最深的是 ahyangyi 使用了一個很有進攻性的策略,如果採用淘汰賽,可能就是冠軍了。對我來說,通過現場比賽,有機會和老朋友重逢,並結識了許多新選手是我最大的幸事。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧。今天到了 2007 年初的東京,回顧一下 2007 世界總決賽發生的趣事吧。

ACM-ICPC World Final 2007 —— Mobile Robot 東京決戰

2007 年的東京 ACM-ICPC 全球總決賽在櫻花盛開的 3 月初拉開序幕。成立了一年的 Mobile Robot 憑藉 2006 年 ACM 上海賽區的冠軍,代表清華參加了此次 ACM 盛會。

記得黃金雄教授在杭州 2008 時說, ACM 總決賽的實力分佈由原先的美洲獨霸逐漸轉向了現在的亞歐爭霸。 2007 年,同樣來自亞洲的上海交大具有很強的奪冠實力,歐洲 2007 年雖然沒有頂尖高手 Petr 和 tomek 的參與,但是 ACM 傳統名校 St. Petersburg , St. Petersburg IMFO , Warsaw , Saratov , Petrozavodsk 等都派出了極其豪華的陣容。雖然在 2000 年前後美洲隊伍成績不佳,但是近些年由於衆多歐洲選手的加盟,美洲 MIT 等頂尖名校也在總決賽中表現得非常強勢。

記得,每次世界總決賽之前, TopCoder 的論壇上都會羅列出所有參加總決賽的 TopCoder 選手名單。但是我不是很看重這些數據,因爲在很多次與歐洲選手切磋之後,我發現了自己與歐洲選手相比的一個重大缺陷:我參加各類賽事以來,起初比賽過程中常常受壓力的影響很大,很難正常發揮自己的水平。後來情況有所好轉,在大多數比賽中都能正常發揮自己的水平。可是,令我感到意外的是,許多來自西方的選手在巨大的壓力下,反而表現得極其興奮而能超常發揮出自己的水平。來自西方的各隊,我相信他們只要達到了興奮的狀態,都擁有獲得冠軍的實力。去年上海交大總決賽總結中,他們也提到了自己沒有發揮出應有的水平,而 IMFO 即使在比賽壓力下仍然能夠做出 8 題,可見他們平時訓練實力之強。但是我覺得現場比賽發揮受影響可能是少數中國選手的壞習慣,可能不適合用同樣的思路分析歐洲的頂尖高手。

抵達東京:

出發的前一天晚上,我仍然熬夜參加了 TopCoder 上的 SRM 比賽,竟然是 Petr 出的題目。當時我與 Petr 的 Rating 差距很小,當時我 3 道題目都交出了很高的分數,在 System Tests 之前遙遙領先,但是 500 和 1000 分的題目都由於一些很小的粗心而失敗了。我也失去了在總決賽之前超過 Petr 的大好機會。結果到達日本之後的第二天,吃早餐的時候,我就碰到了作爲教練來到東京的 Petr ,他一看到我就扯前天比賽的事情,汗。現在回想起來,那場 SRM 對我的總決賽之旅確實有不小的負面影響。

抵達東京之後才發現,所有隊伍中,只有我們選擇了與所有志願者衣服顏色相同的清華校色紫色,開幕式過程中,許多隊伍都把我們當成志願者了。

練習賽前一天的晚會很豐盛,大多食物都是中國風格的,水果也非常好吃。晚會期間,我見到了衆多大陸學校的隊伍,當年大陸至少有 15 支隊伍參加總決賽,隨處可以感覺到說着國語的選手。同時還見到了許多 TCCC 上出現過的面孔,隨後發現 ardiankp 也來參加了,我們還聊起了 ACM 在新加坡( ardiankp 是代表南洋理工大學參加的)的情況。類似總決賽這樣的比賽,我覺得選手之間的交流則更重要了,因爲每次總決賽都會集結衆多熟悉的 ID 但陌生的面孔。晚一些之後,我們與北京大學的 T2 一起打牌,隊友 geworm 和 wd.h 都抽籤到了另一方,他們的牌太猛了,在加上我和李文新老師的牌都不好,結果我們慘敗。

從正式比賽的前一天的中午開始,主辦方組織我們遊玩當地的 Disney 樂園。日本 3 月的景色很美,當地人也很熱情,唯一的缺點就是無論用日語還是日式英語都很難交流。我們在 Disney 樂園中主要以觀看錶演爲主,沒有參與過多的活動。東京到了晚上有些冷,我嘴脣都有些結冰了,可是發現路上許多日本女高中生還穿着裙子,仰慕。

正式比賽:

總決賽的隊伍是按照學校的音序排座位的,練習賽時我們發現自己坐在來自荷蘭的上屆亞軍 Twente 大學旁邊,剛打招呼就發現他們 3 人的最低身高也有 190 ,據說荷蘭女子的平均身高也有 180 以上,似乎覺得自己是從小人國來的。

練習賽過程中,我已經絲毫感受不到娛樂的氣息了,現場的緊張氣氛已經籠罩了我們全隊。所有隊伍都在抓緊一分一秒熟悉比賽環境,賽場中敲擊鍵盤的聲音已經完全覆蓋了觀衆鼓掌的聲音。比賽中使用的 PC2 提交系統比想象得穩定,我們努力嘗試各種功能以熟悉機子上的編程環境。東京的總決賽使用了一個形狀奇特的鍵盤,由於當時早已養成了自帶鍵盤的習慣,這次總決賽中奇形怪狀的鍵盤對我編程的速度影響非常大。

總決賽正式比賽在第二天 9 點左右開始, Bill 想盡各種辦法活躍氣氛,不過比賽開始前幾分鐘現場還是靜得可怕,比賽開始 5 分鐘之後,現場就被鍵盤聲籠罩直到結束。我們回顧一下比賽的過程吧,底紋的文字是我比賽後寫下的總結:

這次 World Final 的題目又基本由編程題組成,可能是由於比賽時不夠興奮,比賽全程都非常不順利。

大概從 2003 年開始,世界總決賽的題目風格已經完全倒向以編程題爲主的特點,對此我們早有準備。不過由於時差問題,還有幾天前 SRM 比賽由於錯兩題導致 Rating 跌停對我信心的影響,使我比賽中一直不是很興奮。不過比賽過程中,我們仍然堅定的採用前面提到過的常用組隊模式:

(1) geworm 全程負責讀題,思考算法和出數據;

(2) wd.h 和我在比賽前 2 個小時一起攻簡單的題目;

(3) 2 小時後 wd.h 就開始死磕難題,我主寫程序一直到 3 個半小時左右,結合 wd.h 對難題的把握,大家開始合攻難題。

25 分鐘: Problem A ,簡單地枚舉。可是我生物沒有學好,沒有考慮父母基因的順序問題,錯了一次。

比賽開始時,正常情況我會從 B-I 中間尋找容易上手的題目。可是由於有些緊張,直到 geworm 給我翻譯 A 題目內容時,我還沒有讀懂任何題目,這種情況很少發生。

題目 A 的描述,需要一些必要的生物知識幫助理解,可是這些東西我早已忘記。 geworm 花了不少時間幫助我理解這題,我還是由於沒有考慮父母基因的順序 WA 了一次。不過改過來之後,我們竟然是所有隊伍中第一個通過 A 題的,可見當時很多隊伍也沒有完全放開。

43 分鐘: Problem B ,最長上升子序列。開始算法沒有想好,莫名其妙地錯了一次。

如果說題 A 的 WA 是生物問題,那 B 的 WA 簡直就是莫名其妙。 B 就是最長上升子序列問題,好像剛開始寫時我和 wd.h 都沒有想清楚,寫了一個神鬼莫測的程序, WA 一次之後才改成正確算法。可是當時我們都沒有想到的,總決賽中我們隊伍莫名其妙的 WA 噩夢纔剛剛開始。

97 分鐘: Problem G ,枚舉 + 模擬。這是很扯淡的一題,題目很容易看錯,我們由於看錯題目錯了兩次,等看到 Twente 大學過了之後才重讀題目,找到了正確的理解,浪費了大量的時間。

G 的題目描述確實不是很清楚,許多隊伍都發生了理解錯誤,我們也不例外。不過第 2 次提交錯誤就不能理解了,當時也不知道出於什麼原因又提交了第二次,難道是想先搶一個提交冠軍嗎?當時我們確實受到了開局不順利的影響,這樣做在罰時本身就落後的情況更是下雪上加霜。

146 分鐘: Problem F , BFS 。其實這題是我發揮編程能力的機會,但是我開始用了一個很奇怪的搜索方法,錯了一次才改用 BFS 過了。

在 G 題迷茫而放棄之後,我又嘗試實現了 F 。 F 的第一次 WA 是我們 Final 之行的第三次 “ 莫名其妙 ” 了,我也不知道自己用了什麼一種奇怪的搜索方法竟然過了樣例,還馬上提交了,面對這種情況我有些着急,表現得很不冷靜。好在 geworm 及時提醒,我馬上改成 BFS 過了。在這期間, wd.h 已經實現出了 I 題,並提交了一次,結果是 WA 。

178 分鐘: Problem C ,排序 + 枚舉。這題有一個陰險的地方,就是 theta=0 的情況,還好我們考慮到了,這也是我們唯一一次 AC 的題目了。

C 題的算法其實非常清楚,陰險的情況我們也考慮到了,我終於沒有再搞笑一次,這也是我們唯一一次 AC 的題目了。從通過 C 的時刻講,我們的形式還是很有利的,因爲難度很大的 I 我們已經實現得差不多了。

224 分鐘: Problem D ,數學題。這題本是一道很簡單的數學題目,但是不知出題人怎麼想的,搞了一些沒有任何意義的東西,真是這次題目的一大敗筆。我們開始由於沒有注意三點共線的情況錯了 3-4 次,然後由於 int64 越界又錯了 3-4 次,最後錯了 7 次才 AC 。這題一共浪費了 1 個多小時。

在 BGF 各一次奇怪的 WA 之後,我們又完全陷在了 D 題的陷阱之中,如果順利的話 D 題只需要 15 分鐘就可以寫完,可是我們忘記考慮了 D 題中很多的陰險情況,拖延了 1 個多小時,貢獻了 7 個莫名其妙的 WA 。可是,當時我並沒有想到,這已經是我 AC 的最後一道題目了。

227 分鐘: Problem I ,數學 + 模擬。這題是 Jelly 寫的,有很多特殊情況。

平心而論,我在總決賽上的狀態不是很好,編程速度受到影響,而且有 10 次以上的錯誤提交。最後我們 7 題的罰時高達 1200 多,而上海賽區同樣 7 題的罰時只有 700 多,從這一點上也可以看出當時實在不在狀態。不過, wd.h 很好地執行了我們預定的組隊模式,順利完成了拖後中衛的角色。在我通過 D 題之後,他改正了 I 程序中的最後一個 bug 。 I 題最終也只有我們和華沙兩支隊伍通過,可是說是我們最終能夠獲得亞軍的殺手鐗。記得在頒獎儀式之前,基本上所有選手見到我都問 I 怎麼做,我都統一回答:是胡偉棟做的。

我們依靠 I 題的 AC 首次排在了榜首。比賽進行了 227 分鐘,能夠在 200 分鐘之後獲得領跑的機會,我首次看到了奪冠的希望,上海和西安賽區的歡呼場面一次又一次從我眼前閃過。當時只有華沙大學通過 6 題,其他隊伍都還不超過 5 題。

可是幸福只持續了短暫的 3 分鐘,我們由於罰時太多而被華沙反超,華沙大學通過第 7 題時華沙隊員的反應幾乎瘋狂, ICPC 的工作人員也用照片記錄了這一時刻。

Problem E ,我們的算法應該是正確的:二分答案 + 最短路。但是不知程序犯了什麼錯誤,沒有 AC 。

Problem H ,很複雜的幾何題目,我們的算法是:掃描。但是不知程序又哪裏寫錯了,結果是 WA ,不是 TLE 。

雖然在接下來的 73 分鐘時間內我們沒有再過題,不過我們仍然拚殺到了最後一刻,拼盡全力而無怨無悔。無論是 E 還是 H ,我們都想出了正確的算法,並且成功寫完了程序,但是 Judge 給出的結果一直是 WA 。我們不斷測試數據,並修正了一些 bug ,但仍然不能通過第 8 題。在這種情況下的穩定過題能力我們確實特別沒有訓練過,華沙能夠通過 8 題的超強實力確實很讓人敬佩。比賽剛結束時, Petr 還特地趕來問我們有沒有通過第 8 題, ICPC 的工作人員碰巧留下了照片。

當時我很希望能夠借他的運氣得到一個 Yes ,不過 PC2 還是不斷返回 WA 直到最後。

後來, E 題就成了我寫計算幾何題目的一個巨大的心理障礙,直到 2 個月前在 Proxima 的一次訓練中,在隊友的支持下,我終於成功通過了一個更強版本的 E 題(題目在 UVA 上,題號是 11425 ,這題至今 2009.1 也還只有我和東京冠軍隊的 marek 通過)。

Problem J ,這是一道很複雜的算法題目,現在我還不能證明算法的正確性。更重要的是這題很容易實現一些看似正確的算法,可能沒有做這題是我們這次比賽的唯一成功之處。

I 的算法大致如下:

(1) X_i = the mininum cut between V_i and V_0.

(2) while (the graph is not empty)

{

(3) m = min(X_i).

(4) remove all nodes V_i whose X_i=m.

(5) let X_i = min( X_i , m+ the mininum cut between V_i and V_0 ).

}

(6) return X_1.

這裏提一個公開的祕密,最後顯示華沙大學的結果時,他們成功通過了 E 題,可是比賽過程中,我們並沒有看到他們掛起藍色的氣球,不知道來自浙江大學或者中山大學的選手能不能仔細回憶一下,當時你們應該坐在他們旁邊。

頒獎:

最終,華沙大學以通過 8 題的成績獲得冠軍, Mobile Robot 通過 7 題總用時 1200 分鐘獲得亞軍。整場比賽,我們克服了開局的種種不利因素,成爲全場第一支通過 7 題的隊伍,亞軍也是一個非常可喜的成績了。由於華沙大學不來自亞洲,我們同時也獲得了亞洲冠軍。

頒獎儀式之後的表演很精彩,印象最深的要數那位 “ 神偷 ” 了,他在觀衆面前不斷施展 “ 妙手空空 ” ,觀衆掌聲不斷。記得表演結束後大家等電梯時,那位演員從我們身邊走過,我們都連忙確認自己的錢包和手機。 ACM-ICPC 東京總決賽在一片片掌聲中落下帷幕。

總結:

ACM-ICPC 總決賽結束後, Mobile Robot 又恢復了平靜。 Mobile Robot 成立以來共獲得了兩個分區賽冠軍和一個總決賽亞軍,從那之後 Mobile Robot 就宣佈解散了,也許唯一的遺憾就是沒能獲得一個真正的世界冠軍。賽後,黃金雄教授也來向我們祝賀,從他的言語中,我們也感受到了一絲揮之不去的遺憾。

東京總決賽的幾天裏,我有機會結識了許多國內外朋友,也是這次日本之行的一大收穫。同時也感謝衆多 ACM 選手一年來對我們的關心和支持,當時 bbs.pku 上留下了一個很長的帖子,讓我永生難忘。

在現場比賽中,我數次與歐洲選手直接交手,對他們的特點有一定的瞭解:

(1) 歐洲選手的編程能力很強,很適應總決賽現有的題目風格。有些歐洲選手在 notepad 裏寫程序,然後直接提交的事蹟絕非傳說。

(2) 歐洲選手對於算法的靈活運用能力強,但是對於一些比較深的算法瞭解不多。例如此次總決賽的 J 題。

(3) 許多歐洲選手的現場抗壓能力很強,即使在最後時刻仍然可以發揮出自己的水平。

在總結過復旦和 Srbga 出題的風格之後,總結一下我理解的總決賽題目風格吧:

(1) Srbga 大哥出的題目和世界總決賽的題目風格近似,題目對編程能力提出了極高的要求。相比之下大多數題目對算法的要求不高。

(2) 總決賽題目對算法的考察範圍非常廣,但是對於某特殊的算法要求不高。

(3) 總決賽題目的時間限制很寬,出題人很提倡一題多解。而且數據沒有想象得苛刻,隨機算法有用武之地。

東京的總決賽已經結束快 2 年,今年寒假結束之後,我又要準備踏上總決賽征程了,希望這次我們 Proxima 能做的更好,將總決賽名次提高一位。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧。今天總結一下國際個人賽場吧。

國際個人賽場 —— 三大賽事

ACM-ICPC 總決賽結束後, Mobile Robot 就宣佈解散了,也許唯一的遺憾就是沒能獲得一個真正的世界冠軍。宣佈退役 ACM 之後,我仍然連續參加了那之後的每一場世界範圍的現場編程比賽,按照時間先後分別是: TopCoder Open( 簡稱 TCO)2007 , TopCoder Collegiate Challenge ( 簡稱 TCCC)2007 , TCO2008 以及 Google Code Jam( 簡稱 GCJ)2008 。每次比賽,我都度過了一段美好快樂的時光。

TopCoder 公司與三大賽事:

TopCoder 公司大概在 9 年前成立,成立的原因有些讓人匪夷所思,據說公司創立者原來是另一家 IT 公司的大股東,在把原來公司的股票轉手之後換了一筆錢,開設了 TopCoder 公司。然而 Topcoder 和原來的 IT 公司有一個重要協議,就是 Topcoder 在創立之初的兩年內不得從事軟件開發的工作。於是 TopCoder 在前兩年時間內以類似競賽的方式從事軟件開發的活動。經過 9 年的發展,現在 TopCoder 公司已經基本由算法競賽轉向軟件開發了。

TopCoder 公司除了在網上舉辦 SRM 之外,每年還舉辦 TCO 和 TCCC 等現場賽事(當然還有 TCHS ,不過規模比較小,參與面也不是很大), TCO 和 TCCC 分別在每年的 6 月和 11 月舉行,每次大賽都能匯聚衆多國際編程高手。另外, Google 公司從 2000 年開始,先在各大洲舉辦名爲 Google Code Jam 的比賽,從 2002 年開始也舉辦全球範圍的 Google Code Jam 。於是這些年來,大家一直把 TCO , TCCC 和 GCJ 稱爲三大賽事。

2007 年之前的 GCJ 都是使用 TopCoder 的比賽形式, Topcoder 的算法競賽有點類似於 IOI , ACM-ICPC 之類的競賽,題目是同一個類型的。每次比賽三道題目,一般分數分配爲 250-500-1000 ,比賽分爲 Coding , Rest , Challenge 和 System Test 四個階段,時間各是 75 分鐘(現場比賽 85 分鐘), 5 分鐘, 15 分鐘(現場比賽 10 分鐘)和不定。

TopCoder 的現場比賽都由 3 個階段組成:所有選手被分爲 3 個組(稱爲 Room1 , 2 , 3 ),每組分別進行半決賽,每組前 2( 或 3) 名直接晉級決賽, 3-6 名晉級 wildcard 比賽, wildcard 比賽 12 人中的前兩名填補決賽的最後 2( 或 1) 個名額,決賽由 8( 或 10) 名選手參加。由於三大賽事的比賽形式相差不大,每次現場決賽的選手中總是有許許多多熟悉的面孔。

三大賽事的波盪起伏:

可能細心的同學能夠發現疑問,在文章最開始的一段中,我表明自己在 2007 年之後沒有錯過任何現場賽事,那爲什麼沒有 GCJ2007 呢?其實原因很簡單, Google 公司在 2007 年全年中只舉辦了面向美洲的比賽,沒有舉行面向全世界的公開賽。 GCJ2007 的擱淺也使得整個 2007 年只有 TopCoder 公司獨自舉辦世界大賽。

但是,當大家以爲 GCJ 將在記憶中淡去的時候, GCJ2008 重新登陸,而且新的比賽環境與形式給選手以煥然一新的感覺。這裏先談談自己對這種新比賽環境的看法吧:

GCJ2006 仍然使用的是 TopCoder 標準形式,也就是說和 TCO 以及 TCCC 完全一樣,用一句話概括就是 Coding-250-500-1000-Challenge-SystemTests 。

GCJ2008 比賽環境結合了 ACM , TopCoder 還有 IPSC(ipsc.ksp.sk) 等多種比賽的特色。

(1) 每道題目分爲 Easy-Hard 兩組數據,並且數據可以下載到本地,這點好像與 IPSC 很相似,另一個與 IPSC 的共同點就是,不限制選手使用的編程工具,包括肉眼觀察或者人工搜索。

(2)Easy 數據則和 ACM 非常近似,即時提交評測,並且也設定了每次失敗提交加 4 分鐘的罰時。

(3)Hard 數據則更像 TopCoder 的形式了, Hard 數據由於是統一評測, System Tests 可以有效

地把懸念保留到最後一刻。

GCJ2008 的比賽形式是一種大膽的嘗試,並且也已經有了很理想的結果。

另外,值得稱讚的是, GCJ2008 中首次使用了分各大洲進行當地現場半決賽的賽制。使得排在前 500 名的選手得以參加各大洲的半決賽,也拉近了 Google 公司與選手之間的距離。從另一個角度來說,各大洲半決賽的方法很有效保證了決賽選手的水平。平心而論, TopCoder 現場比賽前的最後一輪網絡淘汰賽對選手的壓力很大,就連 Petr 在 2007 年都直接來了一個 “ 滑鐵盧 ” ,連現場賽都沒有進。而現場比賽的公平程度遠超過網絡賽,所以通過現場賽決定決賽選手可以一定程度上提高決賽選手的水平,至少我個人很贊同這種做法。

擱淺的比賽無獨有偶,可能是受到了 2008 年全球經濟危機的影響, TCCC2008 也停辦了。而且我們都覺得, TCCC2007 很可能是 TopCoder 舉行的最後一次 TCCC 了,當然 TopCoder 這樣做沒有不合理的地方。

TCO 則相對穩定一些,就連每年舉行的地點都不變, TCO 連續 3 年在著名的賭城 Las Vegas 舉行。今年應該也不會改變地點。

三大賽事的舉辦,我覺得選手最大的受益就是,比賽提供了一個到美國免費遊玩的機會。我先後去過 7 次美國,其中 6 次都是參加編程比賽。通過比賽的機會,我們得以開闊眼界,結交朋友。我個人真心希望三大賽事能夠繼續舉行,但是 2009 年秋天的 TCCC 和 GCJ 很可能同時停辦,這也是一個不可迴避的問題,讓我們拭目以待吧。

美國之旅:

從 2007 年以來的 4 次現場比賽,雖然每次比賽過程中都有一些遺憾,但是現在回想起來都有不盡的樂趣。

TCO2007 是我第一次到達賭城,一下飛機就看到很多賭場 (CASINO) ,可誰知 TCO2007 整個比賽過程就是一場巨大的賭博。我當時由於不熟悉 Texas Hold'em 的規則,在半決賽中搞錯了 Flush 和 Straight 的大小關係,結果初上賭場就傾家蕩產而被淘汰出局。 TopCoder 比賽中竟然出賭博有關的題目,果然有 Las Vegas 的特色呀。不過在賭場裏,我仔細研究了許多賭博遊戲的規則,然後寫了幾個程序計算賭博的期望,但是發現標準概率模型下所有遊戲的期望值全是負數(其實挺顯然的),於是,也就以娛樂爲目的和 lympanda 切磋了一下。

如果說 TCCC2006 的 Room1 是中國的勝利, TCO2007 的 Room1 則是中國的失敗了,雖然 Ying 和 lympanda 都進入了 wildcard ,可是都由於一些小失誤輸掉了這次賭博。賽後 lympanda 請我去牛排館吃飯,後來那個牛排館也成爲每次 TCO 比賽我們中國選手的主要聚會地點。

TCCC2007 的小組賽還比較順利,我輕鬆擊敗了 gawry , Per , marek.cygan 獲得小組第一挺進決賽。可是決賽中,我爲了提高速度以超過 Petr ,再加上有些緊張,最後 500 分和 1000 分兩題又都掛了,落到了第 5 名。 TCCC2007 地點設在了奧蘭多,比賽結束後我們到附近的 Disney Land 去玩,那裏的驚險遊戲比國內刺激得多,有些遠遠超過我的極限,我們一行人一直玩到深夜才返回。許多選手還一起到奧蘭多魔術隊主場觀看了 NBA 現場比賽,可惜最後一節成爲了垃圾時間。

TCO2008 我也依靠飄逸的 1000 分題中 800+ 分的提交闖入決賽。決賽前我還和 visualage 聊天,誇耀自己從來沒有所有題目全掛,更沒有拿過負分。可是在隨後的決賽中,這兩個 “ 夢想 ” 就都實現了, PE 對我的評價是太緊張了。基本每次 TopCoder 現場比賽都能見到 PE ,誰知他每次懷疑我某些題目的正確性的時候,我的程序就一定是錯的,如果下次我參加決賽,您就不要再看我程序了吧(呵呵,開個玩笑)。

不過在決賽 Challenge 階段的最後時刻,我從第一視角目睹了 Petr 和 Tomek 的巔峯對決。在還有 15 秒鐘結束時 Petr 還落後 Tomek 大概 30 分左右, Petr 成功 Challenge 了一個超過了 Tomek ,但是 Tomek 利用短短的 10 秒鐘也提交了一個成功 Challenge 又超了回來,誰知 Petr 得到這個信息之後又提交了一個 Challenge ,可是運氣稍差,如果那個數據用來 Challenge 我的程序的話, Petr 就能夠在最後 1 秒再次奪回冠軍的位置。能夠到最後一秒還能有機會成功翻盤的一定是神一般的人物,能夠把神一般的人物逼到最後一秒的也一定是神一般的人物,兩個神一般的人物你來我往,爲大家上演了一場精彩的比賽。

歐洲獨霸:

又一次引用黃金雄教授在杭州 2008 時說的話, ACM 總決賽的實力分佈由原先的美洲獨霸逐漸轉向了現在的亞歐爭霸。但是,我根據這些年的比賽結果發現,從 2006 年開始,團體比賽和個人比賽,特別是個人比賽,歐洲選手一直保持着絕對的霸主地位,亞歐爭霸的說法實在有些牽強。

從 2005 年開始,幾乎所有三大賽事的冠軍都是歐洲選手。成績最好的要數俄羅斯,俄羅斯選手以 Petr , andrewzta 等爲代表。俄羅斯選手訓練刻苦,編程能力極強。歐洲的另一霸主就是波蘭,波蘭選手具有很強的靈氣,以 tomek , marek 以及 Eryx 爲代表,程序設計在他們手中體現出了藝術氣息。

前幾天我也看到關於取消 NOIP 保送 資格的文章,我沒有發表評論,因爲我沒有看懂,爲什麼文章裏把保送和保送資格混爲一談,讓人覺得哭笑不得。這裏我對 保送 資格還是想法不多,不過想比較一下我們中國選手與歐洲選手思維能力上的差別。

在高中時,吳文虎老師就常說中國選手的 IOI 成績很優秀,的確這幾年從 IOI 成績上看,中國是絕對的霸主。可是 ACM-ICPC 的成績,俄羅斯和波蘭等強隊的成績卻遠在中國之上。於是我們總結的原因是:歐洲選手的編程能力強。我非常同意這個說法。

但是 “ 歐洲選手的編程能力強 ” 的說法並不說明他們的算法能力弱,相反他們的思維素質非常高,他們具有非常正統和嚴密的思維方式,體現出經過長期訓練的思維能力和素質。

我覺得中國的 “ 高手 ” 和許多通過高考進入名校的 “ 神人 ” ,在大學之前接受的教育都是以選拔爲目的的,並沒有太多針對思維方式和能力的訓練。記得小學要考重點初中,初中則拼搏重點高中,高中期間則夢想名牌大學,而在學習期間,我們並沒有太多機會訓練自己的思維能力,至少在我的中學階段是這樣的。雖然很多高中已經竭盡全力通過類似研究性學習的方法鍛鍊我們的創新能力,但是仍然不能改變選拔性考試 “ 高考 ” 這一事實。而在與西方選手交流的過程中,我覺得許多思維能力優秀的學生很早就有機會接受系統的思維能力訓練,尋找最適合自己的思考方法。我一次有機會看 Eryx 留下的草稿,發現他考慮問題有非常嚴密的過程,從理解題目到想出算法每步都有根有據,並不是隨機碰撞的結果。

現在歐洲選手與我們相比,思維能力上也並沒有劣勢。我有幸在投身 OI 競賽之後,得到許多機會與其它選手交流,學習他們的思考方法,努力鍛鍊自己這方面的能力,試圖與衆多歐洲選手對抗。

Mountain View 登頂:

GCJ2008 在 Google 總部 Mountain View 舉行,賽前我想用 Ying 的一句話來表達我對比賽奪冠的渴望, “ 我雖然獲過很多獎,但是缺少一個世界冠軍 ” 。早在 GCJ2006 ,我就擁有機會獲得冠軍,但是在失去那次機會之後一等就是整整的兩年。

比賽開始不久, bmerry 的強勢起跑使我逐漸失去了奪冠的念頭,只得一心做好眼前的題目。 bmerry 在不到 2 個小時的時間裏就做出了除了 C- Hard 以外的所有題目,他只要在最後一小時做出 C- Hard ,就基本上可以鎖定冠軍了。

不過我克服開場的不順利之後,磕磕碰碰地在 2 小時過 5 分順利通過了 E-Easy 和 E-Hard 。擺在我面前的只有 B-Hard 和 C-Hard 。 B 題和 C 題相比之下, B 題我已經有了一定的想法,可是 C 則是完全沒有想法。於是我決定先做 B , GCJ2008 的 B 題簡直是我的剋星,我先後用了 100 分鐘時間做這題都沒有結果,可以說當時狀態很差。大概到了 2:40 的時候,我查看 board 時突然發現了一件令人窒息的事情, bmerry 已經嘗試了 C-Hard 並且超時了。由於 C-Hard 的分數略高於 B-Hard ,我最後想要超過 bmerry 就必須做出 C-Hard 。果斷放棄 B-Hard 之後,並沒有想出 C-Hard 的方法,寫了一個搜索程序但是心裏很沒底, Hard 數據的提交時限是 8 分鐘,於是到了 2 小時 52 分的時候,我毅然打開 C-Hard ,用搜索的程序運行 C-Hard ,在焦急的等待之後,程序在運行了 1 分多鐘以後神奇地運行結束了。我依靠搜索方法通過了 C-Hard ,一舉超過了 bmerry 。 1 分鐘後 zhuzeyuan 也做出了同樣的題目,超過了 bmerry ,由於罰時排在第 2 名。我和 zhuzeyuan 還有 bmerry 比賽過程中都有不小的失誤,我很有幸把失誤的損失降到了最低點,終於獲得了第一個世界比賽的冠軍。

這次 GCJ 的題目有非常詳細的解答,可以在比賽的鏈接裏找到。 GCJ2008 的比賽結果從一定意義上,打破了歐洲選手多年的獨霸場面。加上原籍南非的 bmerry ,前五名中都沒有出現歐洲選手的名字,這也是在多年現場比賽中沒有出現過的。

這一年,我很高興看到 OI 選手中出現了 ahyangyi , yuhch123 , Loner 等各方面都極爲出色的新人,真心希望你們能夠早日適應大學的學習生活,再創佳績。

衆多新人的加盟,大大提高了清華 ACM 團隊的實力。在 2008 年,清華大學 ACM 隊創紀錄地獲得了 4 個分區賽的冠軍。明天最後一篇回憶中將分享 ACM-2008 中發生的趣事。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧。最後是 2008 年的杭州復出。

2008 年 ACM-ICPC —— 杭州復出

2006 年 ACM-ICPC 總決賽結束後, Mobile Robot 就宣佈解散了,也許唯一的遺憾就是沒能獲得一個真正的世界冠軍。宣佈退役 ACM 之後,我並沒有完全與 ACM 絕緣,每次 TopCoder 大賽之前還常常做一些 ACM 比賽調整狀態。記得 08 年初,我也全程觀看了總決賽,不過沒有想過復出。


杭州復出: 
一切事情要從一個 zhuzeyuan 的電話說起,時間是 11 月 8 日 晚上 10 點左右,當時我正在參加 UVA 在線比賽而爲 GCJ2008 作準備。 zhuzeyuan 在電話裏首先告知我 Loner 車禍的事情,好在現在 Loner 已經痊癒了,當時確實很擔心。隨後, zhuzeyuan 向我介紹了 2008 年 ACM 比賽的進行情況,當時北京和哈爾濱賽區已經結束。然後,邀請我加入 Proxima 參加杭州賽區的比賽。我想當時答應的原因主要有 3 個: 
(1) 我個人很喜歡 Coding ,雖然退出 ACM 已經快兩年了,但是還經常參加個人比賽。剛剛結束的 GCJ2008 中國區半決賽,出人意料的奪冠增強了我的信心。另外, ACM 這樣長達 5 個小時的團隊比賽造就了很特別的環境,賽場上的氣氛和激情是做裁判教練或者參加個人比賽中無法體會到的。 
(2) 3 年前的 2005 ACM 杭州賽區,我留下了我大學生活中的一大遺憾。對於杭州 2005 的慘敗,我一直想尋找機會從那個跌倒的地方爬起來,徹底擺脫紫金港校區留下的陰影。 
(3) 其實還有一個原因就是我家在杭州,而且在本科期間我也曾經到杭州電子科技大學做過關於 ACM 的報告, lcy 老師的熱情給我留下了深刻的印象。 
對於 Loner 的車禍,我也覺得非常意外。這也是對於我們常年在校園騎自行車裏橫衝直撞的警示。 Loner 現在能夠恢復得這麼好,我們都很高興,祝你明年 ACM 好運。 
加入 Proxima 的手續很順利,教練鄔老師對我復出想法的回答簡單扼要:研一學生可以參加 ACM 比賽。 
Proxima 的另外兩名隊友分別是 zhuzeyuan 和 zhouyuan (周源),我加入 Proxima 之後,新 Proxima 先後進行了 3 次訓練比賽,隨後就出發到杭州電子科技大學參加 2008 年 ACM 杭州賽區的比賽了。 
當時,我通過許多網上資料和 zhuzeyuan 的描述瞭解了當時清華的戰績。到杭州賽區之前,清華的 What ’ s Up 和 IronGods 已經分別獲得了哈爾濱和北京賽區的冠軍。其中 IronGods 還獲得了哈爾濱賽區的亞軍, What ’ s Up 則一起來到杭州參加比賽。 Proxima 在杭州賽區之前已經參加了北京賽區的比賽,成績是第二名。就當時的形勢講,我們沒有資格考慮太多事情,如果想保留懸念就必須獲得杭州賽區的冠軍。


杭州賽區現場賽: 
在杭州賽區練習賽那天的上午,我們抓緊一切時間進行了模擬訓練,選擇的題目是 NEERC 的題目。題目難度有些大,我們做滿整整 5 小時,直到 12 點 50 才急忙去吃午飯。結果很晚纔到達比賽場地,到時候練習賽已經開始很久了。希望我們的遲到沒有影響旁邊隊熟悉比賽壞境。 
杭電賽場的環境很好,在賽場裏我找回了 2006 年上海賽區的感覺。隊伍之間的空間很寬敞,電腦桌也很大,足以讓 3 個人在上面一起推導公式。馬上就見到了 lcy 老師,不過他帶來了一個不太好的消息 —— 不允許自帶鍵盤。好在杭電提供的鍵盤很標準,對我們影響不大。 
正式比賽在第二天早上 9 點開始,回顧一下比賽的過程吧: 
在 Proxima 隊中,比賽開始時,仍然由我準備編程環境,然後從中間開始讀題。我馬上發現了 D 是一道看似簡單的題目,並且也注意到了這句話:

WARNING: a naive algorithm might not be sufficient to solve this problem.

但是沒有想到的是 BFS 算法也算是 naive algorithm ,我交出了全場第一個提交,結果是理所當然的 TLE 。不過那句 WARNING 稍微有些飄逸。

zhuzeyuan 發現 A 是簡單題目,於是我馬上寫 A 。

19 分鐘, A :判斷兩張圖的修改距離。枚舉全排列,統計即可。

A 是最簡單的題目,由於開始 D 的耽擱,我們大概是全場第 4 個出題的隊伍。

接着, zhouyuan 發現 J 也很簡單,於是我轉向 J 。

28 分鐘, J :允許刪點的並查集問題。通過添加新點的方法實現刪點。

過了 J 之後,排名暫時上升到第一位。隨後, zhuzeyuan 發現沒有新題可寫,於是就開始寫 C ,過程中,我和 zhouyuan 發現 G 比較簡單,於是插空寫 G 。

50 分鐘, G :簡單圖論問題。開始刪點判斷錯誤造成 WA 了一次。

59 分鐘, C :高精度計算和素數判定問題。這題是 zhuzeyuan 寫的。

不到一個小時就通過了 4 題, Proxima 獲得了一個很好的開局。對於杭州賽區難度的題目,能夠在第一個小時通過 4 題已經很順利了。對於許多分區賽中會出現更多的簡單題目的情況,有時能夠做到一小時 5 題。但是一小時 6 題實在太難了,記得我們在一次訓練比賽中做到了一小時 6 題,已經是我們的能力極限了。

接下來我實現了一下 B ,可是由於發生了理解錯誤,計算結果與題目要求計算的結果直接存在重複排列問題,只好把程序放在一邊。

隨後, zhuzeyuan 開始實現 H ,提交之後我開始寫 F 。

95 分鐘, H :計算幾何,如果使用 O(n2) 的算法需要注意常數不易太大。

105 分鐘, F :自動機判斷相等問題,通過計算差乘的方法能夠在 O(n2*|Sigma|) 內解決

H 的提交等了很久, H 的 Yes 出來後不久我就寫完了 F ,提交之後也 Yes 了。大概在 2 個小時左右我們做出了 6 題,其實如果不在 B 上浪費時間能夠更早一些。在 2008 杭州賽區,我們又一次獲得了 6-4 的領先優勢。

下面我們面臨一個比較困難的狀況, E 和 I 看似都比較複雜,但明白題意的 B 和 D 都沒有想出算法。 2008 年杭州賽區的題目中,基本沒有中等難度的題目,所以我們通過 6 題之後就直接進入了比賽後期。當時我們分了一下工,我決定死磕 D 題, zhouyuan 負責推 B 題的公式。 zhuzeyuan 嘗試新題目 E 或者 I 。

我的工作進行很不順利,先實現了一個普通的 A* 算法,由於優化得不好還是 TLE 。現在回想起來, D 題標準 A* 算法中使用的那個優化還是挺巧妙的,至少很有藝術感。我放棄 A* 算法之後, zhouyuan 似乎已經推好了 B 題的公式,開始幫助我實現 D 題。

163 分鐘, D :狀態最短路徑問題,通過 A* 算法加一些優化可以輕鬆通過。

zhouyuan 提出了一個很重要的優化方法,先通過解方程的方法判斷是否有解,在確認有解的情況下使用雙向廣度優先搜索,程序寫好之後又 TLE 了。不過我覺得運行時間已經差不多了。於是,我使用了卡節點的方法,終於在第 5 次提交通過了 D 。 D 題我們用了大概一個小時左右。這時 What ’ s Up 早已通過 5 題,不過由於他們卡在 H 題上,我們仍然以 7-5 領先。

zhuzeyuan 確認 E 和 I 比較複雜之後,我們開始合攻 B 題。 zhouyuan 其實受到了我原先錯誤算法的誤導,他得到一些公式來計算繁衍函數,通過繁衍以及原先程序的結果得到正確結果。不過,從當時的形式看,這樣也是很不錯的選擇。

程序很快就寫好了,提交之後又是奇怪的 TLE 。 B 題的 TLE 和 D 的 TLE 本質完全不同, B 題我們算法的複雜度是 O(n4) 的,對於 n<=20 的數據範圍,時間上應該沒有問題。於是,我生成了 100 組測試數據,發現總共只需要 1 秒左右。

在 B 題的這一點上,我覺得命題人做的很不合理,雖然此題存在 O(n3) 的算法,但是既然把範圍出到 20 ,就應該允許 O(n4) 的算法通過。可是命題人一共疊出了 6000 組測試數據,使得我們的程序超時了。而且在 Clarify 中的回答是 1000 多組,我們優化程序之後還是一直 TLE ,當時我們怎麼會想到是 6000 多。至少這裏的範圍 20 極具誤導性。幸好, zhuzeyuan 及時想出了一個解決方法 —— 打表。由於對程序沒有信心,打表的 15 分鐘時間內我們 3 人都只得通過手工計算簡單數據來確認程序的正確性。

236 分鐘, B :比較複雜的動態規劃,需要考慮 4 種情況。

打完表之後提交終於得到了第 8 個 Yes ,時間是 236 分鐘,距離封版只有 4 分鐘。由於 6000 組的陰險數據,我們從第一次提交 B 題到通過 B 整整用了 50 分鐘,而且是 3 個人一直在一起做。

封版時,我們仍保持了 8-6 的領先優勢。但是接下來,我們犯下了杭州 2008 最大的錯誤,如果類似的錯誤在總決賽中出現,我們將很可能失去領先位置。當時我們沒有看到港大掛起 E 的氣球,於是在 E 和 I 中選擇了 I ,結果深深地陷在了 I 的無底洞中,直到結束都不能自拔。

I :模擬題,需要考慮的情況比較多。

E :計算幾何。計算半平面的交。

現在回想起來, E 題的難度遠沒有 I 題大,我們錯誤估計了 I 的難度。非常敬佩賽場上通過 E 題的港大和 I 題的湖南大學,你們不愧爲射鵰英雄。

清華 2008 戰況:

2008 年,清華延續自己在 ACM 大陸賽區中的霸主地位, 4 支不同的隊伍獲得了創紀錄的 4 個不同賽區的冠軍。分別是:

1. What ’ s Up —— 哈爾濱賽區冠軍

2. IronGods —— 北京賽區冠軍

3. Proxima —— 杭州賽區冠軍

4. ZCS —— 成都賽區冠軍

從 ACM 的規則上講 4 支隊伍都獲得了進軍總決賽的資格,清華總決賽隊伍的選拔過程在成都賽區結束的第二天就開始了。

從我的角度描述另 3 支隊伍的情況吧:

What ’ s Up 是清華第一個獲得冠軍的隊伍,杭州賽區的過程中,他們以 amber 主寫程序的模式進行,在比賽開始階段體現出了很強的衝擊力,不過卡住 H 後的慌亂略顯出組隊模式的缺陷。雖然他們在杭州賽區之後就選擇放棄了總決賽資格的爭奪,但是我們都深知他們的實力。後來 What ’ s Up 的成員擔任了 PK 比賽的裁判工作。

ZCS 由剛進入清華學習的三名大一學生組成,成員是 yuhch123 , Cheryl 和 ScaleRhyme 。我參加 Proxima 之後沒有和 ZCS 交過手,不過在 Ural 和 SGU 上比賽時看到過 ZCS 的身影。在杭州賽區之後, ZCS 在成都賽區創造了 7/7(7 提交 7 通過 ) 奇蹟,不過和北京賽區相似的是後期略顯經驗不足。隨後, ZCS 沒有參加校內 PK 賽。

IronGods 的組成是 OpenGL , ahyangyi 和 ghy 。在 IronGods 成立之初,我一直很看好這支隊伍。哈爾濱賽區結束後,記得 ahyangyi 還來和我抱怨比賽中的失誤,那道高精度題目確實有些過於複雜(呵呵,不過至少數據沒有錯誤)。北京賽區的情況,我是事後聽 dzx 介紹的, IronGods 依靠最後一小時的穩定發揮,通過 3 題,一舉壓倒 Proxima , Carriage 和 ZCS 獲得冠軍。可是幾天後,我驚奇的發現自己需要面對強大的 IronGods 了。

IronGods 的組合與新 Proxima 驚人得相似, IronGods 的 OpenGL 與 ahyangyi 還有我和 zhuzeyuan 都是 TopCoder 上的 Target (中國一共有 7 個 Target ,另外 3 個是前輩 haha , lympanda 和 ZCS 隊中的 yuhch123 ,看好 zhoujie 成爲第 8 個,加油呀!),他們的編程能力與我和 zhuzeyuan 不相上下。從 TopCoder 的成績上看,我們兩人的速度略快。

另一名隊員 ghy 和 zhouyuan 都很擅長思考算法, ghy 結束 OI 時間比較短,狀態保持得很好, zhouyuan 對於深入的算法瞭解比較紮實(北京的 A 很贊呀!)。

從配合上說, IronGods 組隊時間長,配合方面比我們默契許多。我們重組後雖然也進行了一些訓練,不過在比賽中普遍交流偏少,特別是我和 zhouyuan 的交流,在後幾場比賽中才有些成功的配合。

不過從穩定性角度看,我們稍占上風, TopCoder 上的 Volatility 值至少可以說明一些。而且 ACM 比賽時間長達 5 小時,穩定性的要求應該比 TopCoder 還高一些。

清華校內 PK :

後來, zhuzeyuan 代表 Proxima 與 IronGods 協商之後,大家決定採用三局兩勝的賽制,並定下了 3 場比賽的時間和題目安排。

關於總決賽隊伍的選拔,我個人非常不贊成直接指定,可能與我的一些經歷有關吧。已經進入研究生學習的我,對參加總決賽已經沒有兩三年前的激情了。不過我個人的觀點是,如果學校指定,我對於 4 種結果都可以接受;如果進行 PK 選拔,賽場上我一定拼盡全力。

兩場 PK 過程中,我們都在 bbs.pku 上發佈了現場的即時排名情況。由於清華 ACM 團隊有嚴格規定要求對兩次 PK 中使用的題目保密,我這裏就只留下了比賽的大致過程。

第一場 PK ,時間和吉隆坡賽區完全相同,過程大致如下:

Proxima 啓動比較快,到 2 小時左右就獲得了 5:2 的領先優勢。

題 F 是這場比賽中我們最大的失誤, F 浪費了很多時間,而且最後都沒有過。

IronGods 利用 Proxima 卡住 F 的時機連追 4 題,以 6:5 反超。

發現 IronGods 反超之後,我又嘗試了幾次 F 題,但還是不能通過。比賽還有 70 分鐘結束,而且我們手上並沒有其他題目。 zhuzeyuan 在關鍵時候毅然決定開始寫 J ,記得他說的一句話是 “ 沒有時間了,我必須開始寫了 ” ,當時形勢不容樂觀。好在 J 成功 1Y ,士氣大振。

Proxima 隨後連過兩題重新佔據 7:6 優勢。

最後, IronGods 追成 7:7 平,比賽又打得難解難分。

IronGods 最後時刻也還有機會,我們又一次目睹了 IronGods 的絕地反擊實力,可能他們最後做 H 的選擇值得商榷。

第一場 PK 過程中兩支隊都有明顯失誤的時期,我們由於失誤在中期,所以罰時較少。最後依靠罰時險勝,在 PK 中佔得先機。

第二場 PK ,時間設在 12 月 25 日 的晚上進行,題目編號從 A 到 L ,共有 12 題之多。第二場 PK 比前一場進行得更激烈,過程中兩支隊伍都長時間保持了很好的狀態,比賽過程中多次交換領先位置:

開局 Proxima 起步略快, 65 分鐘就通過了 5 題 BDEFK 。

開局看似順利,不過我們都明白:真真的比拼還沒有開始。

Proxima 卡在了 H 和 C 上, IronGods 通過了 BCDFK 追成 5:5 平,罰時 Proxima 領先。

IronGods 通過了 G ,首次反超 6:5 。

Proxima 經過 rejudge 通過了 H ,出現了 6:6 平,罰時 Proxima 領先。

Proxima 第 10 次提交才通過了 C ,再次獲得題數領先 7 :6 。

如果輸掉了這次 PK ,題 C 則是最大的敗筆。

IronGods 通過了 J ,追成 7:7 平, IronGods 在罰時上領先。

此時的罰時落後就是 Proxima 在 C 題上出錯 9 次的惡果。

Proxima 第 4 次提交才通過 G ,以 8:7 反超,但罰時還是很大。

IronGods 通過了 H ,又追成 8:8 平,利用罰時 IronGods 再次獲得領先。

這已經是第 6 次出現平分了。這時還不到 3 個小時,校內 PK 賽的題目難度並不在 2008 杭州賽區的難度之下, 3 小時的 8:8 的高比分平局是現場比賽中很難看到的。而在高比分平局中罰時也是很重要的,此時 IronGods 佔據明顯的優勢。

Proxima 經過 rejudge 通過了 I ,再次超出 9:8 。

Proxima 通過了 J ,優勢擴大到 10:8 。

記得題 J 的第一次提交開始的返回結果是 “ Other-Contact Staff ” ,看到這個回覆之後 zhuzeyuan 馬上跑到 Judge 室,在被工作人員擋住之後, zhuzeyuan 很奇怪地問道 “ 難道不是你們讓我來 Contact 的嗎? ” ,囧死了。不過很快就 rejudge 成 Yes 了,題 J 的通過也從一定意義上逆轉了罰時的不利, IronGods 如果想翻盤就必須在最後一小時重新上演北京賽區封版通過 3 題一幕。

Proxima 通過了 A ,優勢擴大到 11:8 。

記得最後提交 A 題的時候,我緊張得手都有些發抖了。當時只剩下 25 分鐘, IronGods 還沒有開始寫 A 和 L 兩題,所以在最後的時間裏他們已經不可能通過餘下的 4 題了。 A 題的 Yes 也就成爲了這場 PK 的勝利宣言。

IronGods 最後時刻通過了 I ,最終題數爲 11:9 。

此次校內 PK 的激烈程度決不亞於 2006 年上海賽區,能夠最終贏得這場 PK 使得我們更有自信地站在總決賽的現場。

首先感謝關心我們的同學,記得第一場 PK 當天正在舉行吉隆坡賽區比賽, bbs.pku 上還是出現瞭如此多的帖子爲我們雙方加油。第二場 PK 結束時已經是晚上 11 點,我們手機還不斷收到祝賀短信。

向 IronGods 三位天王致敬,在 PK 過程中只需略微的變化,出現在斯德哥爾摩的就很可能是你們。棋逢對手是我 ACM 生涯的一大幸事,相信你們明年一定能夠做得更好。

我想這是清華第一次使用公開的現場 PK 方式來選拔總決賽隊伍,個人覺得 PK 的方式除了公平之外還有許多優點。首先, PK 方式可以使得各隊伍能夠更從容地選擇和準備不同的分區賽賽區,有效提高學校的總體成績。其次,通過 PK 的過程,可以加強各隊之間的交流,隊伍各方面水平能夠得到全面提高。真是一舉兩得。

利用假期空閒之時,將這幾年 GCJ , ACM , TopCoder 參加的一些重要比賽作個回顧,包括今天一共 10 篇。接下來的重要比賽就是世界總決賽了,縱觀世界總決賽各隊,雖然形勢不容樂觀,但我們一定會拼盡全力。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章