顯示具有 Bipartite-Matching 標籤的文章。 顯示所有文章
顯示具有 Bipartite-Matching 標籤的文章。 顯示所有文章

2015年4月26日 星期日

MSBOP 2015 Qualification Round & Round 1A (Updated 2015-05-03)

親愛的Peter神得知我想有一件T-shirt後介紹的一個新比賽
由M$主辦 確實條件很簡單 只要在能advance到Round 2就有T-Shirt了

這個比賽的流程是 Q-Round-->Round 1A / B (各500名advance)--> Round 2 --> Final
先來說結果吧 我Round 1A 不打算玩的, 所以遲了一小時多開始玩, 結果AC了 3題中最多分的一題, 但因為太遲玩 + 錯了一個白痴錯誤, 只有504名
今天全力玩Round 1B, 狀態卻奇差, 也進級失敗, Round 1止步了

然後是一些我對這個比賽 / 平台的comment
每場比賽跟GCJ一樣只有3題, 題目也有趣的
但我還是很不滿

首先, 這個平台沒有練習模式, 賽後想再submit試試看也沒有機會
也沒有Solution 跟Editorial, 有幾題真的我認為pattern很常見卻不會做的題目
我真心很想知道思路啊...

就結果來說, Qround我就不特別寫了...沒什麼好寫的, 打得也不特別好
A跟B應該都會做的, B-Large自己白痴交了個TLE的solution, 之後其實改好了
但正如我所說的賽後根本不能submit試試看能不能過...唉

C是完全沒想法, 開頭以為是那個簡單的分開 x 跟y axis來算optimal value的技巧
卻完全不是, 問了GG 也說有點難做就不了了之, 這是一題我很想知道思路的題目

來到沒認真打的Round 1A, 遺憾是有的, 要是認真打的話應該advance = 有T-Shirt了..
Round 1A的3題:

A 我真心認為是語癌, 它的sub-tree跟我認識的好像完全不同意思, 題目也沒特別說明它的sub-tree是不是common說的sub-tree..總之是語癌題, 果斷跳過
感過要不是語癌的話, 應該是中等易一點的dp on tree...

B 我認為是最難的一題...也是另一題我很想知道思路的題目
給了 n (< 1000) 個直角等邊三角形, 斜邊都在x-axis上面, 三角形可以overlap
你可以決定要build那一些三角形
build一個三角形的收入 = w_i  -  它的area
要是某部分有overlap的話, 那部分只需要算上一次就ok
問最大可能的收入是多少

感覺很像knapsack類的dp, 但overlap area 背後的trick 完全沒想通
總之就沒多少想法就是了...真的很難

C 是我唯一過了的一題...竟然small + large有45分, 根本沒多難的...
但這題是唯一我想記下的, 因為還是很有成功感的說


MSBOP 2015 Qualification Round

(2015-05-03) 先更正下對這個平台的看法, 過了數日後終於能夠賽後Submit了
結果還算是合格的平台吧...

至於比賽的Editorial 還是沒出...看來這堆題目要成為遺憾了
之前 (上面) 所講的 Qround B-Large 雖然是白痴開錯了array size
但即使不開錯也不算是太易過的,,,終歸還是在運氣+摸魚的情況下過了...

至於C-Large, 還是沒想法, GG也沒更進, 果斷把它從腦中丟掉比較好

A: (Ad-hoc)

找潤年的基本題目...就按住題目給的定義判定下就好了...

B: (DP)

Q-Round來說重點是這題吧...找Peter神試了一下, 他也認為不算是容易的,,.
所以就記一下吧
DP來說我認為也是有趣的一題...思路可以學習一下 (原來可以這樣DP的啊)

題目是這樣的 (以Large來說), 給了string S 一條 (|S| <= 1000)
問有多少Subsequence 是palindromes...

注意是subsequence 不是substring, 所以也不算太直接
由數據來說, 應該是O(n^2)的DP
(好像做過palindrome相關的題目不是DP就是Greedy?)

問題是怎樣dp 才能不超時...
由於O(n^2), 又是palindrome
狀態應該是近於 DP(x,y), x跟y 是S 內的range這樣...

我是用Top-down的做法的 (bottom up不太會code那個順序...這些事其實也不用強求)
Top-down內不能有for loop吧, 不然就不是O(n^2)了...

然後在紙上畫兩畫, 發現了一個有趣的Observation:
首先設DP(x,y) 為position x 到 y (inclusive)之間所有palindrome subsequences的總數
然後大約是 S[x] 跟S[y]慢慢拆走再看DP(x+1, y-1) 是常識吧....

那麼會出現S[x] == S[y] 或 S[x] != S[y]兩個情況

先看 S[x] != S[y]的情況
由上圖能發現, 
DP(x,y) = A+B+C-2C, 要 -2C 是因為 A+B的子狀態時會重覆算了C的子狀態2次...
所以 DP(x,y) = A+B-C = DP(x+1, y) + DP(x, y-1) - DP(x+1, y-1)

再看 S[x] == S[y]的情況
首先, 要explicitly 加上 1, 因為S[x]S[y] 自己已經是一個palindrome, 而這個palindrome不能由任何子狀態 (A,B OR C) 算出, 所以要自己把答案 + 1

然後就跟上面差不多了
DP(x,y) = A+B+C-2C+C, 要 -2C 是同樣原因, 要+C 是因為 C跟 S[x]CS[y] 是兩個狀態分別數了兩個 disjoint set of palindrome subsequences, 兩個disjoint set 的size 跟都是 C 那個狀態的Size...

所以 DP(x,y) = 1+A+B+C-2C+C = 1+A+B = 1 + DP(x+1,y) + DP(x,y-1)

就是這樣了...combine 兩個case 一下可以很簡單一行code就完成
至於時間複雜度嘛...Recursion的complexity我從來都不太懂算
但由於沒有for loop, 而每個狀態都會把 [x,y] 的range縮少至少 1
x跟y 只有O(1000) 也就是最多只會有O(n^2)個狀態, 每個狀態算一次這樣 (with memorization)

MSBOP 2015 Round 1A

C: (Math, Bipartite Matching)

這題簡單來說, 是Math + Maximum Bipartite Matching
有成功感的原因是, 除了它高分以外, 是以為不多久前學的Maximum Bipartite Matching
終於派上用場了, 果然如我當時所說的, 性價比真的很高
而且思路也是從當時某一題題目引申出來的, 再從這一題學到了另一個 fact
(詳情請自己找回之前Bipartite Matching那篇文)

我直接以large的數據來說一下

題目給了 n (< 1000) 個數字, 2個數字 a, b  (a<b) 叫prime dependent iff  a*p = b for some prime p

問這n 個數字 最大的subset where subset內任何2個數字都是prime independent的subset size
這些數字 < 500,000

直覺認為跟prime factorization脫不了關係, 打質數表也是必需的, 500,000內的質數還是很少的(5000個左右)

然後就在紙上畫了畫 把sample case都畫了一下
畫的方法是把 n 個數字內 prime dependent 的都連上一條線, 這樣就得出一個graph

然後不難發現, 答案就是這個graph的 Maximum Independent Set!
這個問題我也知道是NP-Complete的, 而在題目中有NP-Complete的情況只有幾種:
要不是 n 很小, 可以用某些dp 暴試之,
便是這個NP-Complete的題目在某些條件下不是NP-Complete的, 例如General Graph下的問題在Bipartite Graph下通常都很易解的

這也是一樣! 這樣就引至我逆轉去懷疑, 題目給出的這些Graph其實是不是 Bipartite Graph呢?

這個要prove也不算難, 基本上證明graph中沒有"三角形"就好了...

Case 1: 假設 a, b < c,  然後 a跟c 有edge, b跟c也有edge, 證明 a跟b之間不能有edge
--> Given a*p1 = b*p2 = c
assume a跟b 有edge , then a*p3 = b
-->  a*p1 = a*p3*p2 = c
--> p1 = p3*p2
--> contradiction as p1 is not prime now!

Case 2: 假設 a < b,c,  然後 a跟b 有edge, a跟c也有edge, 證明 b跟c之間不能有edge
--> Given a*p1 = b,  a*p2 = c
assume b 跟c 有edge, then b*p3 = c
--> a*p1 = b, a*p2 = b*p3
--> a*p1 = a*p2/p3
--> p1 = p2/p3
--> contradiction as p2 is not prime now!

--> 這個Graph 是bipartite的!!

好了, 接下來, 我記憶中 Bipartite Graph中的independent set 好似有解的
...好吧, google了一大輪, 原來我記錯了

其實...Bipartite Graph 的Minimum Vertex Cover 才是有解
Min Vertex Cover =  Max Bipartite Matching

然後...經由推理 (這個其實已經足夠肯定)
再加上google wiki, 就肯定了以後事實:
For Any Graph
Max Independent Set = # of vertex - Min Vertex Cover 


在Bipartite Graph的情況下, 
Max Independent Set = # of vertex - Max Bipartite Matching

這就出現算法了!

先打質數表
再用 O(n^2) 建圖
然後在圖上找Max Bipartite Matching...

咦?
Maximum Bipartite Matching 可是要 O(V^3) 或者O(VE)啊...
前者是用matrix來儲圖, 這個題目一定不行了
只有O(VE)可行... (用adj, list來儲圖)

但...這不是等於要 E = O(V)嗎?
這下又要證明一下了...(其實真正比賽時可以直接去了...感覺根本就是正確做法, 不用懷疑)

這個證明比賽時沒很全做完...事後再試試嚴謹一點的

我想證明這個Bipartite Graph不能有cycle ( i.e. even cycle)
也是用contradiction來證明:

證cycle存在, cycle中最小的數字叫a, 最大的叫z
則
a*p1*p2*...p_n = z  (一直按最長的path由a走到z)
同時
a*p_x = z (a跟z 直接連起來的edge)

則p1*p2*...p_n = p_x
-->contradiction as p_x not prime!

由於不能有cycle, 所以最多只能有 V-1條Edge了
QED!

Code起, AC了
遺憾的是Code仍是要出cheat的...concept是記得, code卻沒有上手呢...

結語: 這題真的會比題B難嗎...

結語2: 今天認真玩的Round 1B比1A更加強差人意, 就不特別記下了...倒是很想有賽後submit作practise用的機制呢...還有solution啊....M$ Why you suck so much

結語3: 有開始在看KMP / String相關的算法了, 我沒有忘記要寫一篇String Searching的詳細文, 這才是原本的步調...但看來要在Code Jam Round 1B後再說了...希望1B別比1A難吧..








2015年2月2日 星期一

Bipartite Matching Basic & UVA10418 大冒險

說好的Bipartite Matching...難得學了一些基本又做了一些基本題目
當然要留個名...

話說所有理論/證明/寫法都是參考演算法筆記的, 這個神網真的幫了我很多
以下全部都是向未來的我的自白:

 To 未來的我:

基本要說的都可以在裡面找到了...這裡只留下一些讓"你"更易回憶/理解的思路...

首先 Bipartite Matching與General Matching的關係很深, 基本上General Matching
的算法 (雖然還未看)都是以Bipartite Matching的算法加以變通, 明了一就應該明了全部...

然後所有Matching的題目好像都可以用Flow相關的算法來解 (不肯定)...
可恨我也不會Flow..慢慢再學起吧...=.=

再來Matching的算法複雜度基本還是很高的...題目要求如果不太大 (~10^2 - 10^3?)
特徵相附的話, 很可能可以用Matching過的

Bipartite Matching的算法實作起來100%是DFS (相信General Matching也是)
不難寫, 但背後概念要很清楚...
另有一版本是BFS取代DFS, 複雜度更低但好像有點難寫....

Matching 問題以我暫時理解可以有3種: Max/Min Cardinality, Max/Min Weight, Perfect Matching
沒有Weight的情況下, Max Cardinality = Perfect, 有Weight的考慮則很多變化, 也不是這篇的主題 (其實是還不懂=.=)

所以這篇就是學基本中的基本: 沒有Weight的 Max. Cardinality Bipartite Matching
雖然是所有Matching中最簡單的, 出奇地很多題目都用得上, 攻利地說算是性價比高吧...

OKOK, 有點長氣...入正題吧..

理論 / 算法

Bipartite Matching基於一個理論: Augmenting Path Theorem (Berge's Theorem)
證明很勉強地理解了, 但不會記下的..."你"有興趣自己回演算法筆記看吧...

首先定義Augmenting Path (跟Flow 那個Augmenting Path不知有沒有關係?)
是一條兩個end points都是未匹配點的梅花間竹path



這類path的特性是: 把path上的邊逆轉, 匹配的變成非匹配 (and vice versa) 則總Matching Cardinality會+1

然後 Augmenting Path Theorem證明的是: 圖上任意一個不能作Augmenting Path起點的未匹配點, 把它移除, 剩下的圖仍能找到原圖其中一個Maximum Matching

這直接導出最簡單, 基本的Bipartite Matching算法: Augmenting Path Algorithm
設G={X,Y}  X跟Y是二分的兩組vertex,  隨便選X或Y都可以, 把它們全都當作未匹配點
然後一個個試著找Augmenting Path, 找到的話Cardinality就加1了, 同時該點會變成匹配點
如果找不到的話, By Augmenting Path Theorem, 我們移除它 (或者直接不管它)就好了
每個點要不變成匹配點, 要不直接不管, 都是Access一次而已
而當中找Augmenting Path的部分則是用一次DFS (或者用BFS, 如上面所說)
這個很重要, 直接簡單地分析了複雜度:  V次DFS的複雜度
DFS又視乎圖用什麼結構,  Matrix的話是O(V^2),  List的話是O(V+E) = O(E)
所以整個Augmenting Path Algorithm 是 O(V^3) 或者 O(VE)

基本題目

先來看幾說基本題目, 各自都有得益

UVA259, UVA10092

題目很直接的就會讓你聯想到Matching
然後這道題也有很多Bipartite Matching的特性...
就是建圖的麻煩!  很多時要自己想個簡易的方法給vertex一些id
才能用Augmenting Path Algorithm去解!

例如這道題, 題中的一些貌似vertex的東西可以重覆使用數次, 例如4次
建圖時真的要把它們當時4個分別不同id的vertex!

當初我做的時候, 我自作聰明, 沒用分開4個不同的node, 我用同一個node
讓他找4次Augmenting Path, 其實我到現在還是認為可行的...
test case好像也過的了, 不知怎的就給我WA
結果還是要乖乖把它們分開幾個不同的node才行...這個要記住


UVA10080
也很直接的一題, 就是建圖時計一下距離吧...

UVA10243

哇哇哇, 這題真的可以重點講一下
來頭不小的...可是某年ACM World Final.....的試機題目 (o:
但已經獲益良多了...
如果要說直接題意的話, 其實是求Tree 的Minimum Vertex Cover
老實說 我開頭是完全不明白關Bipartite Matching什麼事...
然後開始發現Tree一定是Bipartite Graph嘛....(所以也可以2-color的)
但...Vertex Cover跟Max. Matching有關係嗎?
用筆畫了畫, 不知怎的好像剛好答案都一樣, 就交了
竟然AC了....

百思不得其解之下, 跑去問Google了, TMD 竟然還真的有這樣的一條Theorem
König's theorem
"...an equivalence between the maximum matching problem and the minimum vertex cover problem in bipartite graphs..."

FUCK...我記住了...
話說General Graph的 minimum vertex cover好像也跟maximum matching一樣的說...?


UVA10418 大冒險

這條真的另開一篇說都不過份...
我為了這題流了多少血汗....
現實來說, 這題是WA的, 但我不知羞恥地認為是UVA Judge的問題
在我看來應該是AC的了...
這篇來看為什麼我這樣認為...

先說一說題目, 題目的變態程度很不一般
因為是劉汝佳"白書"中的題目 (好似係)

題目的running time是30秒 =.=
明顯是告訴你 "量你也做不到"...

題意是這樣的:
Given 一個 m*n的棋盤, 棋盤上有 2*k + 1 隻棋子
k 隻是紅色的, k隻是綠色的,  1隻是金色的
它們初始狀態是放在某些格子上, 同一格可以放多於一隻棋子 (放全部也可以)
然後再選定 t 個格子, 每個格子有一個值叫 r
代表該格子內最後要放 r 隻棋子
所以 t 個格子的 r 總和一定是 2*k + 1
再來是棋盤每一格都有不同高度,  
紅色棋子只能平走或向上爬; 綠色棋子只能平走或向下爬; 金色則無限制地移動
每一步可以選任意一隻棋子向上,下,左,或右走一步 (不能出棋盤外)
由於這樣的限制下, 可能無solution, 所以玩家可以使用一種魔法
把棋上所有棋子換成任意一種permutation, 即把它們任意互換位置

好了, 問題是問, 要達成目標, 最少需要用多少次魔法呢?

只是要理解題目就已經有種吃屎的感覺了對吧?

好吧, 我要高興的是在進一步調查之前, 我的思路基本是正確的...
是要Binary Search + Bipartite Matching的了

先來說說思路跟解法
首先大約的想法是...如何建圖!
這個Bipartite的兩Group很明顯是棋子與 t 個格子了..
而由於有法術跟金色棋子, 基本上每隻棋子都可以去任何一個格子的, 差別在於用多少次魔法
那麼有沒有可能分別找每粒棋子到每個格子的 最少魔法使用數呢?
正確性又如何?

答案是可以的!
正確性建基於一個Observation: 使用魔法的時機, 是在於所有棋子都沒路走的時候!
所有棋子(不包括金色)都沒路走, 其實代表紅色不能再爬上, 綠色也不能再爬下...
解決方法有一個, 而且肯定是最好的, 因為只使用 1次魔法! 把紅綠互換! (各自都是k隻!)
互換後, 所有沒路的變成所有都有路了!

發現這點後, 再來看看建圖的部分, 可以用BFS類似找最短路徑的方法, 找出每隻棋子到每個目標格子的"最少魔法使用數" 這個數字再進一步當成 Bipartite Graph 的 edge weight!

給個例子吧,  假設棋子A 最少用3次魔法可以到目標, 棋子B則要用4次
Physical Meaning是這樣的: 棋子A跟B 各自走這條"最好路徑" (好 = 用最少魔法次數的路徑)
直到沒路, 使用1次魔法; 然後再走下去...重覆3次,  這時A已經到目標了, 而B 還需要多一次魔法
就是說 它們的頭3次是"重疊"的, 可以用3次魔法同時解決它們的困境

說到這兒, 又開始理解Augmenting Path Algorithm的實作時, 自然會想到
用Binary Search去估算 魔法的次數, 每次估算就用一次Augmenting Path Algorithm!
只是找Augmenting Path的時候, 如果edge weight 大於正在估算的數值則要ignore
(就是當沒有這條edge的意思), 這樣確保所有Augmenting Path都能以少於等於
估算數值的魔法次數達成

然後又會發現, 怎麼沒考慮金色棋子?  其實這時再考慮也不遲
以上分析在沒有金色棋子的情況下是絕對成立的, 那金色棋子改變了什麼呢?
最直接想到的是, 金色棋子可以以1次魔法 直接把任意1隻棋子送到任意目標!
實際上, 就是金色先到任意目標, 跟任意棋子互換, 金色自己再次走到任意目標即可

那麼情況產生變化了, 這樣首先發現, 最多只需要2*k 次魔法就可以了, Binary Search的上限!
然後在Binary Search中的Maximum Matching, 假設Cardinality不是2*k+1
就是有某些棋子不能以估算數值內的次數移動到目標了...
那麼自然就可以試試用金色幫助它們吧?
可以想成是: 金色原本去所有目標的weight都是0 , 如果幫助了1隻棋子, 則全部變成1..如此類推
最高可以去到估數算值
所以,  如果 2*k + 1 - #max matching <= 估算數值x  
仍然可以說是成功!  因為剩下的棋子可以全部以金色棋子幫助它們!

呼! 終於做完了!!! Test Case都過了!  為什麼都是WA!
一直WA!!
嗚啊...難得一條非水題....

我心有不甘, 於是上演了我自導自演的偵探日記

首先, 當然是Google了...
出奇的是, 由於這題是變態Asian出的題目, 網上resources非常非常的少
我最先找到的是知名的UVA 解說網站 Algorithmist
它的solution跟我的基本就是一樣, 而且它的test case我都過了...信心大增, 再交
還是WA

UVA Official Forum竟然也沒人問這條...
很絕望, 這時我找到這個Github 上面有一堆UVA題目的solution啊!!
當中也有UVA10418的, 高興死我了
我可以random generate一些input跟它的對比一下再debug了
我也真的這樣做了...結果都一樣, 應該沒問題的啊..!?
難道...難道是它的code也是WA的嗎?  我就這樣把Github上的code 直貼上judge
果然WA了...
這不正常啊...那個Github用家不太像這樣腦殘吧? 把WA的Code放上來陰人嗎?
於是我隨機選了其它數條問題的solution再放上judge, 全都AC了!

這更加奇怪了...這時我跑去UVA Official Forum 開了一個thread虛心求問
果然還是吃白果了

然後我還厚面皮的去StackOverflow問了
果然還是吃白果了, 還不知那個路人給了我一個負皮了 (本來還1-2個正皮的=.=)

然後我還試住找了一下劉汝佳的email 發了一個email給他 (o:
果然還是吃白果了

很絕望的情況下, 我又跑回去Github...
這時我在想, 有沒有機會找到這個Github的作者資料? 
於是我Google這個用家 Bruce3557
發現他在UVA的帳號叫"Monkey D. Luffy"!
而他的確曾經AC了這道UVA10418的!

事情更加奇怪了 我也無從入手了...
這時發現這傢伙在Codeforce上也有帳號啊...叫"bruce3557"
雖然2年沒上線了..我還是試住給他發了一個message

然後竟然今天他給我回覆了!!


我當然打了一大段文字感謝神, 還有請他幫忙verify一下他的code是否亦能AC?
但他沒再回覆了...

話說我也叫Peter神幫忙試了一下, 他也WA了..
然後Peter神給了我一個網站看UVA的Submit Status
發現很久都沒人AC了, 而最近試交這題的除了我跟Peter神
還有一個叫 BrianFry 的神人 (AC了4200多條問題) 也WA了
這個人我認得是UVA Official Forum的常客, 經常回報Bug或是什麼的
可能他看到我在UVA Official Forum 的另一個post吧...

總之事情的發展就是這樣了...我當自己AC了不過份吧? 當它的Judge錯了也不過份吧?
最低限度是太不負責任了吧...說一句"我們試過了, 完全沒問題啊柒頭" 我也會高興點的

再等等看事情的發展吧....(最主要是看Bruce本人在CF怎樣覆我了...)


2015年2月1日 星期日

Codeforces Round #284 (Div. 2)

雖然#281 - #283都有做...
但看了一下好像很麻煩, 所以還是直接跳過
反正最想寫的還是這場 #284
因為它令我跑去學新東西了
話說這場只做了4題, 雖然其中也包括了Problem E啦...

Codeforces Round #280 (Div. 2)


A: (頹題)

頹題...只要沒看錯題目就是考你寫for loop而已=.=

B: (頹題)

也沒什麼算法可言的...就直接做吧, 一題關於STRING PROCESS的頹題

C: (Math)

這題開始有趣了,  簡化一下題意吧

Given n 條線, 它們把空間劃成很多不同region. 然後問你由point A 到point B, 最少要經過多少個region 



應該說, 只要把題目理解成上面的意思, 就變成很單純的數學題了...
由於題目所有point都以(x,y) 輸入,  感覺也不太需要變成vector 來做了

首先發現, 把AB 連成一條直線肯定是經過最少region的其中一個方法 (用Greedy的想法就知道不可能比它更好了) 
然後問題變成, 有多少條線橫跨AB之間?
利用一下簡單的數學特性:  把A點跟B點各自代入 n 條線之內
如果一個是正數一個是負數, 就代表他們被隔開了...
(不會等於0...因為題目說明A跟B都不在任何一條線上)

所以就是O(N) 算一下究竟A跟B是否處在第 i 條線的兩邊

話說實作時, 不能以一句 
  if((sx*a+sy*b+c)*(gx*a+gy*b+c) < 0) ans++;
來算答案...因為.....兩個數相乘會比long long更大...我的兩個WA啊...

D: (???)

沒看題目...而且就AC人數來說, 也沒什麼心情看...

E: (Math, Bipartite Matching)

重點來了! 正正是因為這一題, 我跑去學以前都沒心情學的matching了=.=
發現如果是bipartite graph的matching還是很好理解, 很好code的...
因此還繞了個道跑去做數題bipartite matching的題目....下一篇再詳談吧...

要說這題的話, 絕對不是馬後炮, 一開頭想的算法就已經是答案了...
無奈發現算法中要用到bipartite matching, 所以就跑去學了..

題意大約是這樣的:
有 n 個正整數 n, 再有 m pair 數字(mx ,my), 你可以把位於第mx 個的數字和位於第my 個的數字除任何一個大於1的數字 (要能整除),  同一pair 位置的數字可以選擇多次, 問最多可以執行多少次相除?  Given mx + my 一定是單數, n, m <= 100

是咁的, 由於mx + my 一定是單數, 所以可以選擇的位置一定是 單數跟雙數, 
自然把單數位置的數字跟雙數位置的 分開兩組...

然後由於是問最多可以相除多少次....自然會想到不論選擇那一pair 都會選擇除最小的公因數
最來就是如果一個數字同時可以跟另外數個數字相除,  那不論選擇那一pair 都沒所謂...
反正他也就只有限定數量的"因數" 而已...因數A 跟那一個數字的因數A相除都沒關係, 反正相除數都是加一, 又不影響以後的結果 (1999 MODE)

想到這兒, 不難想像Prime Factorization了吧...?
每個數字都有unique的prime factorization, 那麼把100個數字, 每個數字各自化為自身prime factorization 所有質因數的一堆vertex可行嗎? 
每一個數字 a <= 10^9,  最小的質因數可以是2, 那a 最多可以有 lg (a) 個質因數吧, 大約30個
所以也就共3000個vertex...

算法就出來了, 單數位置一組, 雙數位置一組, 有共同質因數的就連線, 組成一個bipartite graph
找這graph的maximum matching cardinality 就是答案了

好吧, 分兩步來說, 其實主要圖論的題目, 最煩人的都是建圖的部分...
後者的部分基本都是直plug 相關算法而已...

這題的建圖部分, 重點就是prime factorization, 我印象中不懂很快的算法
還是先找所有需要用到的質數吧...我這次用的是新學的改良後的質數篩法
很聰明的一邊打表, 一邊篩, 實際每個合成數只會access一次, 達至O(N)
感覺要一段時間才能理解並記下, 所以先留一個名

實際只要找 sqrt(10^9)內的質數, 就可以做到 10^9 的prime factorization了...
void make(){
    memset(f,false,sizeof(f));
    f[0] = f[1] = true;
    ps = p;

    for(int i=2; i*i < N; i++){
        if(!f[i]){*ps = i; ps++;}
        for(int j=0; i*p[j] < 31630; j++){
            f[i*p[j]] = true;
            if(i % p[j] == 0) break;
        }
    }
}

void fac(int in, int x){
    for(short *pi = p; pi < ps && x > 1; pi++){
        while(x % *pi == 0){
            x /= *pi;
            group[in].push_back(*pi);
        }
    }
    if(x > 1) group[in].push_back(x);
}
然後就是直接用bipartite graph的算法了...
我是用最簡單的augmenting path algorithm, 用adjancency list的話是O(VE)
這個分析有點難...editorial的分析也有人提出了...其實應該也是超時的...不知怎的還是過了..

關於augmenting path 或bipartite matching的算法以及題目, 下篇再說吧...
總之這題做到是很開心吧....學到東西又不算太易...至少對我來說不算很易=.=