2013年4月25日 星期四

Croc Champ 2013 - Round 2 (Div. 2 Edition)



好似係final round, 正式比賽既A,B,C = d2 既C,D,E

剩係做到4題, 但後來對照番正式比賽, 其實200名內(有T-shirt)既好多都剩係做到題A(即d2 C)..
嗚呀

http://codeforces.com/contest/299 <--題目

A:
題意係N個數, 想知有無一個數係大家既common factor

B:
題意係比N個char你, 每個可以係行得/唔行得(石頭)
你可以由原地跳前 1<=i<=k 格,  given N,k 同N個char, 問可唔可以由最左去到最右
永遠都可以最近石頭既空格跳, 即detect有無連續k個石頭


C:

就係正式比賽既A, 如果可以15分鐘內1棍過就有200名內 = 有T-shirt =[
係一題所謂既game, 但其實簡單greedy就ok
基本就係定好每個人最好既pick次序:
1. 兩個都係1一定最大價值, 自己多1對面少1
2. 自己係1 對面係0
3. 自己係0 對面係1
4. 兩個都係0
2同3 唔可以掉轉, 利己 > 損人, 因為自己pick 1 對面下一步只可以pick 番1 (打和) 或者ban 你1 (少你1) 黎對抗, 貪心地諗一定係最好, 反之如果ban 人行先, 去到極端可以出現你咩都無(因為你全部都ban人), 對面有少數1

另外注意下行先個個可以pick先...不過數據好細, 其實照simulate就ok


E:
其實過左都唔覺得特別難..係我數學特別差(所以從來都好憎見到咩number theory個d)
題意大約就係given n (<= 10^14),
solve ordered tuple(a,b,c) for
(a+b)^3 - (a^3 + b^3 + c^3) = n

a,b,c are positive integers

是咁的, 由於數據太大, 基本一定係sqrt(N) / lg(N) 甚至更少去做..當然先試下factorize條式等佢靚仔
呢度就係我覺得自己廢既原因, 我fac極都係出左d 極樣衰既form
結果問左偉大既chin爺, 之後再親身fac多次 無錯
LHS 係 3(a+b)(a+c)(b+c) 黎

其實呢度已經end of story...因為我覺得最難個part都比佢一下講完, adore
之後就係coding 上既問題..

首先 if(n%3)就無解, 跟住先了解一件事...我數底再差都知每一個component都係 <= cubicroot(N)
所以, 就先用O(cubicroot(N)) 黎搵哂合格既factors先
(小插曲, 其實我印象中唔知邊個講過total # of factors of integer N 係O(lg N), 但點諗都唔似係,結果問chin爺, 好似未有確定既Order?)

anyway, fac[] <-- 所有 <= cubicroot(N) 既factors, ~O(10^3)

咁就可以let (a+b) = fac[i]  , (a+c)(b+c) = N/fac[i]
咁樣set係好合理, 因為fac[i] <= N/fac[i] && (a+b) <= (a+c)(b+c)
由, 我唔想數到重複count左一樣既組合, 所以我希望先搵哂所有(a',b',c') where a<=b<=c

用多一個loop j , fix死 a = j,  b = fac[i] - j, 跟住計c出黎 (solve quadratic equation)
最後睇情況,
如果 a,b,c 一樣既就 +1, 如果是旦2個1樣既就+3, 3個都唔同既就+6
處理好唔同order既數目

LL fac[1000005];
LL solve(LL a, LL b,LL t){
    LL c = 0;
    LL delta = (a+b)*(a+b) - 4*(a*b-t);
    LL sq =  (LL)sqrt(delta)*(LL)sqrt(delta);
    //血的教訓, 想test delta是否perfect square, 一定要parse做LL type先..
    if(delta < 0 || sq != delta) return 0;
    LL up = -(a+b)+sqrt(delta);
    if(up > 0 && up%2 == 0) c = up/2;
    //只拎 -b + sq(delta) 就得, 因為另一個一定係負數(如果有)
    //c 已計, 下面處理重點問題
    if(!c) return 0;
    if(a == b && b==c)return 1;
    if(a==b || b==c || a==c) return 3;
   
    //如果c係正數, 先check下有無3個一樣或2個一樣既情況
    //注意呢2個情況一定唔會repeat counting, 唔識用字面解釋, 總之唔會
    if(c <= b) return 0;
    //呢句一定要加, 就係減走d 當3個數唔同時repeat count既tuple
    //當c <= b, 咁c 曾經係之前某次數既a或者b黎, 所以唔使再計
    return 6;
}
int main(){
    LL n,p=0,a,b,c,ans = 0;
    scanf("%I64d", &n);
    if(n%3){printf("0\n"); return 0;}
    n/=3;
    for(LL i=1; i*i*i<=n;i++) if(n%i == 0)fac[p++] = i;
    for(int i=0; i<p;i++){
        for(int j=1; j+j <= fac[i]; j++){
            a = j; b = fac[i]-j;
            ans+=solve(a,b,n/fac[i]);
        }
    }
    printf("%I64d\n", ans);
    return 0;
}

D: (唔識做)
終極變態題..話說開頭睇錯題目..以為係半頹半唔頹既COMBINATORICS..
後尾發現係要<紅色超大>所有</紅色超大>path都唔撞色...
如果問題係成個grid都係吉既任我填, 而且d 色係唔會多過你需要既(即n+m-1種)咁好易數
因為非正式prove左咁既情況所有path既排列一定要一樣, 唔係會影響到某d其它path令佢地撞色
答案係 kP(n+m-1), 由於k == n+m-1, 所以答案即係k!, 例子係example 3,答案係10!
好啦,問題是咁的,
1. 顏色係可以多過你需要既
2. 某d格係已填色, fix死左, 唔可以轉
嗚..

暫時諗到既只有
1. 真正既grid好細 (n+m 大約10之內) 所以做法可以暴力d
2. 似dp + combinatoric
3. 由最左邊"L"型條PATH開始填, 跟住一個個"L"型既path咁填落去
4. 每一個"L"型既某一格, 可以用番上一個"L"型相對應個格既色, 或者一d so far未用過既色

....
唉頭都爆, 放棄鳥 /.\





2013年4月22日 星期一

Some codeforces (Div 2 only) & Croc Champ 2013 q-round & round 1

仲有一個月就完成一年既internship...究竟有無簡錯我都唔知
除左一月至三月好chur之外其實都幾hea 既

唔知點解結果都係搵番d 題目做, 掉低左咁耐結果都係番左黎 =[
的起心肝屋企裝番cygwin set番好environment, 
公司機裝唔到cygwin (o:   直接裝左vim 係Windows cmd

是旦搵左幾場d2 CF 玩, 果然差d 連vim 都唔識用, 慢慢打下google下先好番少少
CF都變左好多, 愈黎愈大型, 我覺得可能大型過Topcoder了
亦都算係一個問contest trick既social platform  

某幾場D2 既CF 遲d先補番..反正都係熱身用
主要都係想留念Croc Champ 2013 

無打一排, 好多野唔記得, 但又有d野以前點都唔明依家好似易明左
例如segment tree...

Croc Champ 2013 Qualification Round


話說通常Q-round d題目應該都易d既, 所以我熱完身就做Q-round先 B-)
果然, TLE / RE 一堆on9 error 出哂黎 :D
最後solve左A-D  

A:
頹題, 就是做 : - /

B
頹廢string parsing, 就是做x2 :/

C:
第一題學番d野既題目。明顯就係brute force, 問題係d code得有技巧又快。有睇過下偶像d code, 立即就知道(其實以前一路都係) bitwise manipulation 完全無sense, 亦都諗得慢, code得唔熟, 呢題叫做可以做番相關方面, 只要熟悉 bitwise operators syntax, 呢題好直接無陷阱

D:
一題IQ題, 題意大約如下: 有一條length n 既array  { a_i = 1 for 1 <= i < n  ,  a_n = 0}
One move := a_i = a_i + a_c   for all i  and any c,   1 <= i,c <= n
目標係用required 咁多move 令所有a_i = n-i
i.e : ;由{1,1,1,1,1,0}-->  {5,4,3,2,1,0} for n = 6
明顯就係可以greedy地做, 使每個number 每move 愈接近target愈好, 因為咁樣可以minimum move就reach target, 如果仲有得行, 就可以將已到target既number + a_n  (i.e: 0)

所以algorithm 大約就係for each a_i, find maximum a_c such that a_i + a_c <= n-i
而由於其實每行一個move, 愈左邊既number一定大於等於右邊既number, 所以其實搵到第一個附合上式既a_c就已經係maximum a_c,  可以cut走d cases

E:
心理恐懼加我懶,  TLDR(A.K.A  TOO LONG DIDN'T READ)
所以無做到亦唔知題目問埋...似係tree 類問題..唔係graph就應該係dp了 (我估)


咁就做完Q-round, 又唔係真係易到咩咁, 難又未至於, 起碼全部都幾ad-hoc既...
所以我就開始做round 1

round 1 好煩膠, 但真係學到勁多野, 係煩左我幾日之後, 終於久違地5條都AC哂 (感動)
而且亦都直接令我搞明左以前一直唔識既segment tree basic concept (感動x 2036)
(不過每題基本都係錯到九彩先AC, 實戰應該比人hack死左 :=[ )

Croc Champ 2013 Round 1


A: 
頹題, 加下減下咁, 就是做

B: 
一開頭比3幅圖嚇死左,諗深一層原來仲頹過A...
直接check 每個node既degree就好, 好似係year 1 csc2100 教d野? 

C:
又係IP, 心諗唔係又玩bitwise野...好彩唔係
原來係玩d再煩膠d既野 (o:
題意是咁的
given n 個digit , n <= 10,
你要用哂(重點) 所有digit at least once,  build 一個ip address, such that 呢個ip address 係palindrome
叫你唔使順次序, print哂所有possible既ip address出黎


FUCK! 


真係好煩..難怪大家都唔做呢題住
首先, 因為IP最多得12位,  你又一定要用哂given 既digit, 又要palindrome, 所以 n > 6 係無解。
好明顯係暴力試...都係個句, 點樣暴力試先會run得快, code得快就係水平既分別
無意中又諗起唔知幾時Joe 爺講過 「唔好以為d暴力試個d煩膠題就唔使做」
so pure so true.

so...每個人都有唔同做法既, 我既做法相當之笨
首先諗辦法 generate 所有"possible"既string,  所謂"possible"既string 就係 length 4 ~ 12
而且given digit 一定出現過哂既palindrome.

generate 方法是咁的, 例如given, 0,1,2,9,
let tmp = "0129", 
我地可以expand tmp, tmp = "0129x" where x belongs to {0,1,2,9}
最多我地可以expand 到 6個位 i.e : tmp = "0129xx"
咁呢d x, xx 其實就係all combination of given digit for certain length ( length <= 6)
可以用dfs backtrack precompute哂先

所以我地就可以generate 哂 由最少2個位至最多6個位既tmp, 

(好煩, 做左/ 識做/ 有更好方法請教我 orz !!)
繼續, 搵個vector 裝住d tmp string, 之後每個possible string sort左佢再用next_permutation()
for 每個permutation, 我地可以generate 相對應既2條possible string:
例如 tmp = "1209" in this permutation loop,  
possible = tmp + reverse(tmp)  or tmp + reverse(tmp - last char of tmp)

終於我地就會有哂d possible既string, 最後每條possible string check() 一次,  睇下ip 個3點放邊個位, 放完之後符唔符合ip 既rule (每一節唔可以0開頭, 唔可以 > 255 etc)
將所有ok 既string  (即ip) 放去一個set
一定要set, 因為有重覆..亦都係我覺得其實唔使咁煩既原因, somehome應該有方法直接搵哂d答案出黎
output set 入面所有string ,  done.

再次請如果有路過人士識做又唔使咁煩既, 請教一教小弟=[

E:
次序上我係做左E先既..所以就寫E先。
無錯, 一題就知係我唔識做既(當時)
但係我又知係SEGMENT TREE, 又見好多人AC, 又見d人code好短, 把心一橫, 我就去搵segment tree既source學去, 結果搵到一番幾好幾易明既 重好有信心既tutorial:
http://poj.org/summerschool/1_interval_tree.pdf

畫兩畫之後...其實發現, 其實唔難(basic)   其實build tree, 應該好standard,
至於query 同 update, 我發現重點其實係2個
1. 每個node 裝咩信息
2. depends on 1, such that at least query / update唔會次次都要search到去node, 因為好似會有機會變左O(N) (唔識prove) 

所以code法簡單同standard, 重點就係你點決定個node裝咩, 跟住相對地改番update / query 咁
順路做左2題poj 入門題一棍AC, 更加有番信心

隨後我見到幾樣都有必要記下既野:
1. BIT 未必做到Segment tree 做到既野, 但Seg Tree基本上咩都做得哂
2. 總之係一d 連續性array 上做統計既題目, 外加要O(lg N) 既好大機會係Seg tree
3. tree array要開N 既4倍 , 我唔知點解, GOOGLE左陣d人話Tree node數的確係2N-1, 但係會有機會搵 current >> 1, 1+(current >> 1)時out of range, 但睇code好似唔會? (因為l == r 時已經return 左, 去到leaf 應該唔會再落..) 請路過人士都可以解釋下
4. 有好幾題都幾出名 (隱約記得training有人講過)都係用到離散化+Seg tree做, 遲d繼續研究, code熟哂d 基本野先

總之, 就係咁, 我就好有自信地番黎做E, 當然又唔係想像中咁易...
題意大約是咁的: 有2條array, 每次query 可以update (a_i, b_j, length), 意思係由b_j 開始計共length咁多格都加上a_i 開始計length咁多格 (相對應既1-1 mapping); 又或者可以問你某一個位置 j 既b_j value.

苦腦左一陣, 究竟一個tree node應該store咩先可以唔使update到leaf呢 ? (因為query 一定要到leaf, 如上面所講, update唔可以次次都去到leaf)  諗住一陣, 我整左個好複雜既structure (o:
 
struct node{
    int l,r,as,bs,t;
}T[N<<2];
 l,r 係range啦,  as, bs 係array a或者b 既起始位置, t 係最新update時間
於是我每次update, 發現該interval 有更新既update, 我就可以直接update 該interval 既as,bs,t
而唔使去到leaf node.

於是query時, 我由tree root開始一路落, 發現有更新既 update t , 就取該interval既as, bs
最後就可以用as, bs, 計番b_j 係該時間點相對應既a_i 。
(有機會無被update過, special handle左好多行...就直接output番b_j)

最後好慢好慢地,  AC左!
再睇人地D CODE, fuck, 人地node structure簡單, code又短又快, 究竟點做到...

D:
2個鐘前又MLE 又TLE (都係自己白痴) 終於AC左...
一路唔知點做, GG 比左提示, 就咁disjoint set 都可以做到, 而唔使用到咩link cut tree / dynamic tree 一d我唔識既野 (o:
題目是咁的
given n 個node及m條edge,  n<=500, m <= 10^4
given k 個query , k <= 2*10^4
每個query係delete 連續某個range既edge (根據input 次序)
問有幾多個connected component

好可怕好可怕..
但根據GG既提示同埋題目講到明要連續地delete, 好明顯"連續"係有d意思的...
尋晚沖涼諗諗下, 又覺得好似partial sum ,  即係可以用a[i] 代表 由0加到i 既sum
咁a[i] - a[j-1] 就係由j 加到i 既sum...之類
確認左呢個方向再諗左好一陣, 就諗到大概方向 (仲未sure code唔code得出)

是咁的, 其實,  首先,  d edge由第0條加到第n 條, 或者掉轉由第n條友到第0條
個graph 都係一樣,  我就諗 其實delete 第i 到第j 條edge 個graph 咪姐係
第0條edge 加到第 i - 1 條edge  <---graph 1
第n條edge 加到第 j +1條edge <---graph 2
兩個合體?

又, 其實我有辦法可以union左呢2個graph, 叫做G' 先好, G' 既 connected component # 就係答案

於是我先precompute 2個"partial disjoint set"
s1[i][j] =  由0加到第j 條邊時既disjoint set
s2[i][j] =  由n 加到第 n-i-1條邊時既disjoint set

之後for 每個query , 我用左少少trick, 用第3個 array 叫merge []

我將 相對應既s1[i][j] 放係merge [0 --> n-1]
相對應既s2[i][j] 放係merge[ n-->2*n-1]
依家merge array 既第 i 格同第i +n 格其實就係refer緊同一個node
所以, 我for all i < n,  union (i, i+n) on merge[] ,

最後數下 merge [] 有幾多個唔同既connected component,  done.

奇怪既係, 我最後一個step用set 數, 會TLE, 轉番用array數反而無事
不過都係好慢 X(




嗚啊, 好想快d pick up番啊, 老細可唔可以唔好比野我做 :(