2011年3月8日 星期二

SRM 499 Div 1 Easy + Medium

又一場不太難的srm呢…或許是srm 500暴風雨的前夕。沒做,其後問GG題目,的確很快想出算法,practice room passed。

250: 給了N個兔子的詢問,代表有多少兔子跟牠同一顏色,假設牠們都是說真話,求最少有多少隻兔子。

不難留意,一個詢問若得出K的話,那麼至少有K+1隻兔子。至於要得出最少答案,不難想象貪心地把最多K個兔子,其詢問都是K的「同化」一下。數式地表示就是求所有(C[K]+K)/(K+1) * (K+1)的和,當中C[K]是指有多少隻兔子的詢問是K。

550: 給了最初空的文件,你可以做以下操作。
1) 找一行插入空格。
2) 找一非空行按下Delete
3) 找一行按下Enter。此時該行會變成兩行且擁有相同的空格數量。

給定最終N行要求的空格數,求最少要多少操作。

留意三個操作疑可看作﹕1) 找一個元素+1 2)找一個元素-1 3)找一個元素分裂成兩個且保持元素數值不變

最直觀的想法就是想用類似最小生成樹的概念去「生成」要求的文件。即每次都找一個最小元素,然後按其最接近已生成的元素求最小的費用(分裂+增加),並加入生成集之中。由此不難看出是貪心且操作2)好像沒甚麼用…而且比較難証明貪心是正確的。因此很快會想到N^3的動態規劃。假定要生成第x~y的元素,那麼就是取其中一個元素來生成,假設是x<=i<=y,然後問生成 x~i-1 和 y~i+1之間的元素最少費用是多少,然後在所有i之間取最少值。
有趣的是,細看這道題的提交,有不同的動態規劃。Petr等高手用的應該是N^4動態規劃,我想這個model是出題者本來預期的答案吧?還有N^3、N^2和種種不同的貪心。最神奇的是三行的代碼﹕

int res = lines[0] + (int)lines.size()-1;
REP(i, N-1) res += max(0, lines[i+1]-line[i]);
return res;


這種貪心,有趣得很。大意就是從左到右以lines[0]為首的連續上升元素,才需要增加用以操作1)的費用,其餘的一律不用。對的原因,我大概想的是,這個序列覆蓋了所有比它小的離散序列的增長費用,因此可以生成這個序列旳時候「順便」生成其他離散的小序列,額外費用只需要憑3)的操作,因此res最初被加上憑3)分裂成其餘N-1個元素的費用。

--
最近兩次SRM題目都很不錯,雖然550是否值得還是很有爭議,但我覺得直覺和經驗相比,總是比較難判斷。

2011年3月4日 星期五

Codeforces #25 E Test

題意﹕給了三個字串,求最短能包含所有字串的長度。

做法﹕暴力枚舉,每次融合一個新字串的時候,考慮三件事。

1) 相互包含。KMP檢測。
2) 字串A前置字串B。A的後綴可以與B的前綴重叠。檢測重叠的方法也是KMP,構造B$A的失敗函數,取其函數最後位的數值即表示前後綴重叠長度。
3) 字串B前置字串A。做法與(2)一致。

需要cut case。即如現在融合字串長度超於最佳長度則中斷枚舉。

Codeforces #17 D Notepad

題意﹕求
看似簡單,但。普通的Repeated Squaring完全不行。
看了一下rng_58的代碼,發覺有一個除了用中國餘式定理以外的做法。

留意﹕若,則有。因此可以用Honor's Rule來算答案。

另,把也是必須的,這步也可以用Honor's Rule來算。

假設,則有,然後根據這個轉移方程算出,若答案為0則直接輸出

對於用字串的來算,則找出從最右邊的數位第一個不是0的數位,把它減一,然後把其後的數位取代成9即可。

2011年2月27日 星期日

Codeforces #51 D Geometrical Problem

題意﹕給了個整數的數組,問其本身是否幾何數列?若否,問能否經移除一個元素使得餘下的數列成為幾何數列?假設

首先,檢測是否幾何數列不難,線性時間就能做到了,另需要特別留意首項為0的情況。但能否高效的做到檢測移除單項成為幾何數列就不簡單。直觀做法是逐一移除,再檢測是否幾何數列,但對於這數據範圍,顯然有點慢。

但,可能的數列等比只有3個(這裡不考慮首項為0的情況,可特別處理)﹕。第三個等比表示移除第二項,第二個等比表示移除首項,至於第一個等比,表示被移除的項在是第3至第N個其中一個。後兩個情況可以再應用一次線性時間的檢測,但第一個情況可以經對比有多少個餘項不符合等比數值即可。若不符合數至少有2,則表示移除第3至第N項其中之一都不能讓數列成為幾何數列。因此本題能以時間內解決。

Codeforces #6 E Exposition

題意﹕給了長度為的數列,取一連續子序列使得其最大和最小元素相差最多為。問該長度最長為多少?並且輸出所有符合條件的連續子序列的長度起點和終點。

很經典的RMQ,可以用Sparse Table或線段樹完成。維護兩棵線段樹,一記區間的最大值,一記區間的最小值。有一個簡單的觀察。

觀察: 對於固定的是一單調上升序列,是一單調下降序列。因此是一單調上升序列。

由此可以,枚舉,然後可以用二分法,二分長度,找出最長的長度使得
最長長度則是

在線段樹查詢區間是,而枚舉加二分長度,整個算法是

2011年2月26日 星期六

SRM 498 DIV 1 Easy + Medium

今次srm miss了,不過Easy和Medium是想不到的容易。也好,最近的srm題越來越難,這些題目應該多出點,有時考核選手的編碼能力和速度也是很重要的。期待以後srm也會多出點這類題目。

Easy
題意﹕要求檢查給定的數列是否符合A[0]~A[a], A[c]~A[d]都是正差等差數列,A[a]~A[b], A[d]~A[N-1]是負差等差數列,A[b]~A[c]元素都是相等,其中。枚舉即可。注意檢查邊界﹕a取值1~N-2,b取值a+a~N-2,c取值b~N-1,d取值c+1~N-2。

Medium
題意﹕給了一個的格子,每個格子都有不同顏色的石子。現在給了個不同的著色的格子,問有多少個不同的石子排列,使得新的排列中,每個石子與著色的格子距離與其原來排列的一致。距離函數是

問題可以看成是pSort的變種。定義某石子的距離特徵為,當中為第i石子與第j個著子格子的距離。不同的石子i, j屬於相同的交換群,若且僅若。因此,對於群組大小為的則有的排列與原來的一致。因此只需把所有不同的群組的排列數取積即可。我則用map<vi, int>來記錄交換群的數量,有點無恥,也有點暴力,但也過了。

Practise room得688分,實際比賽應該打了7折左右,排名可以在31至249之間,可見速度與準繩度有多重要…

2011年2月24日 星期四

Codeforces #60 C Mushroom Strife

題意﹕給了一個邊的圖,每點賦一個數值,每條邊給了,分別代表了。現在只給了每條邊上的,問是否能找到滿足這些邊上的數值的條件。若存在解則輸出任意一組答案。保証

比賽寫了一些錯的東西,因為最初以為正確的做法會很慢………

首先,在每一個連通子圖任意選一點,然後任選一條連接的邊,先求因式分解。而也必然是。因此取值,而且。因此選定後這連通子圖的其他點的值則可以經DFS用求得。

注意DFS時須要檢查取值是否正確的﹕若在一點為一未經過的點賦值,則必需檢查。若已賦值則需檢查

整個算法時間複雜度是

另,注意檢查時小心溢出,即,需要用到64位整數。