JOISC2020 划水記&題解(施工中)
\(Part1\) 遊記
咕咕咕
\(Part2\) \(solutions\)
不會的/沒寫完的先鴿著,補題之後再補
目前只寫了 \(D1T1\) \(D2T2\) \(D3T3\) \(D4T1\)
\(solutions\) \(for\) \(Day1\)
\(D1T1\)
$description : $ LOJ連結
$solution : $
首先有一個\(O(n^2)\)的樸素\(dp:\)
記 \(f[i][j][0/1]\)表示考慮到前\(i+j\)個數\(,\)選了\(i\)個\(A\)和\(j\)個\(B,\)第\(i+j\)個數選的是\(A/B,\)是否可行\(.\)
這個\(dp\)
一種想法
一種想法是考慮構造出一個合法的方案\(.\)
記 \(f[i][0/1][0/1]\) 表示在考慮序列的前\(i\)個\(,\)第\(i\)個選的是\(A/B,\)最多的\(A/B\)的數量是多少\(.\)
考慮從尾到頭構造方案\(.\) 對每個位置列舉這個位置用\(A\)還是用\(B,\)
記當前位置為 \(now,\) 當前位置的字元為 \(c,\) 已經用了 \(cntA\) 個 \(A\) 和 \(cntB\) 個 \(B.\)
那麼方案合法的條件就是 \(cntA\) \(+\) \(f[now][c][0] \geq n\) 且 \(cntB + f[now][c][0] \geq n.\)
按這種方法構造方案即可 \(.\) 複雜度 \(O(n).\)
"一種想法"的正確性證明\(:\) \((by\) \(czynt\) \()\)
如果存在 \(max({a_i,b_i})>max({a_{i+1},b_{i+1})}\)或者\(min({a_i,b_i}) < min({a_{i+1},b_{i+1}}),\)就沒得選擇\(,\)不用考慮他\(.\)
現在考慮\(,\)如果\(max({a_i,b_i}) \leq min({a_{i+1},b_{i+1}}),\)那就是分開的\(;\)
你用這個可以把它分成若干段\(;\)
現在問題就是每一段裡面可不可以任意分\(.\)
我們發現你可以在任意時候跳到比較高的上面去\(,\)就行了\(.\)
\(D1T2\)
$description : $ LOJ連結
$solution : $
一種亂搞
把所有的矩形 cpp random_shuffle()
一下\(,\)然後把前\(k\)個矩形找出來作為起始矩形\(,\)後面的\(n-k\)個矩形用貪心的方法決策和\(k\)個矩形中的哪一個求交\(.\)
這個做法可以過掉賽時的資料\(.\) 然而賽後\(uoj\)上就被\(hack\)了
\(solutions\) \(for\) \(Day2\)
\(D2T2\)
$description : $ LOJ連結
$solution : $
顯然題意相當於我們可以一邊加入邊\((A_i,B_i)\)一邊進行題目中的操作\(.\)
我們把同時存在邊\((u,v)\)和\((v,u)\)的點對合並起來\(,\)縮成一個塊\(.\)
那麼一條兩個塊之間的邊\((cur_x,cur_y)\)對答案的貢獻為\(size_{cur_y}\)
一個大小為\(s\)的聯通塊對答案的貢獻為\(s*(s-1)\)
在聯通塊之間出現可合併的點對時合併聯通塊\(,\)並把某一個聯通塊的所有邊都合併到另一個聯通塊上\(.\)
可以用啟發式合併解決\(.\)複雜度\(O(mlog^2m)\)
\(solutions\) \(for\) \(Day3\)
\(D3T3\)
$description : $ UOJ連結
$solution : $
這題可以分為兩個不同的子任務\(:\)一是\(A=3,B=0,m>=n-1,\)另一個是\(A=2,B=6,m=n-1\)
\(case1:\) \(A=3,B=0,m>=n-1\)
這個子任務的含義\(,\)就是說我有三種標記\(,\)在任意圖的情況下每一步都必須沿著最短路走\(.\)
以下為了方便\(,\)把標記看成顏色\(,\)不同的標記即不同的顏色\(.\)
我們考慮以終點\(0\)為根對給定的圖進行\(BFS.\)記\(dis_i\)為\(0->i\)的最短路\(.\)
\(BFS\)之後\(,\)對於圖中的一條邊 $ (u,v) $ 一定有 \(|dis_u-dis_v] \leq 1\)
換言之\(,\)我們\(BFS\)後的圖就是有若干"層"點\((\) 我們把\(dis_x\)相同的點看做一層 \(),\)其中層與層之間有連邊\(,\)同時一層點的內部也有相互連邊\(.\)
那麼我們需要保證\(,\)對於每個點我們必須能夠讓它能判斷下一步往哪個標記走\(,\)
並且保證下一步一定走向下一層點\(,(\)即\(dis_x\)更小的點\(,\)也就是說\(,\)不能走到\(dis\)更大的點\(,\)也不能通過這一層內部的邊走到\(dis\)相同的點\().\)
所以我們就可以知道\(:\)
\(1.\)每一層的點與下一層的所有連邊應該是同種顏色\(;\)
\(2.\)每一層內部的連邊的顏色應當和前一層連線到這一層的邊顏色相同\(.\)
最後還剩下一個問題\(:\)對於一個點\(,\)
我可能會在int Move(vector<int> y)
中\(get\)到兩種可能的顏色\(,\)但我要怎麼\(check\)哪一種顏色是我這一步需要走的呢\(?\)
有一個(可能)比較精妙的構造 \(:\) 我們可以給顏色設計一個類似石頭剪刀布的優先順序 \((\) 比如 \(,\) \(0>1,1>2,2>0\) \().\)
這樣我們就可以解決這個\(case\)了\(.\)
關鍵程式碼\(:\)
//Anthony 比較長,就不貼了,評測連結裡有程式碼
//Catherine
namespace subtask0{
int A,B;
int work(std::vector<int>y){
int i,s = 0,a = -1,b = -1;
for (i = 0; i < A; ++i) if (y[i]){ if (a == -1) a = i; else b = i; }
if (b == -1) return a;
//這裡的a和b是和當前點相鄰的邊的兩種顏色
if (a > b) swap(a,b);
if (!a && b == 1) return 0;
if (a == 1 && b == 2) return 1;
if (!a && b == 2) return 2;
}
}
\(case2\) \(:\) \(A=2,B=6,m=n-1\)
這個子任務呢\(,\)就是要求我們給一棵以 \(0\) 為根的樹上黑白染色\(,\)然後通過不超過 \(dis+6\) 步能成功走到點 \(0\) \(.\)
由於是一棵樹\(,\)所以對於一個節點\(x,\) \(x\)的父節點只有一個\(,\)而子節點可以有一個或多個\(.\)
如果說一個點的 \(u\) 度數 \(>2\) \((\) 換言之 \(,\) \(u\) 有不止一個子節點 \(),\)
那麼我們就必須 把 \(u\) 與兒子之間的所有邊 設成同一個顏色 \(,\) 且和 $ $ \(u\) 與父親之間的邊 顏色不同 \(.\)
這樣的話\(,\)當我走到的點\(degree>=3\) 或 \(degree = 1\) 時 \(,\)我就能夠簡單的判斷方向 \(,\) 知道下一步應該走哪裡 \(.\)
問題來了 \(!\) 如果有一條直上直下的長鏈\(,\)鏈上所有點的度數都是 \(2,\) 怎麼辦啊 \(?\)
因為度數為 \(2,\) 而根據上述的連邊方式是不能在 \(6\)次錯誤之內 判斷方向的\(,\)所以我們要對現有的方案進行一些修改 \(.\)
具體來說\(,\)我們是要對鏈進行一些修改\(,\)使得在鏈上可以快速判斷方向\(.\)
通過一些人類智慧\(,\)我們有了一個字串\(010011.\)
這個字串有著很好的性質\(:\)我們一旦\(get\)到了他的一個迴圈同構串\(,\)就可以直接判斷是正向還是反向\(.\)
這個字串怎麼用呢\(……\)
我們把這個串的迴圈掛在鏈上 \(,\) 如 \(010011010011...\) 或 \(100110100110...\)
因為\(B=6\) \(,\) 所以我們只能向錯誤的方向最多走 \(3\) 步 \(.\)
但是我們發現走了三步之後正好能\(get\)到串的 \(5\) 個字元 \(,\) 那麼這個串的一個迴圈同構串也就被唯一確定了 \(.\)
至此我們能夠在 \(3\) 步之內正確判斷一條鏈上的方向 \(.\) 如果中途碰到度數 \(= 1\) \(or\) \(\geq 3\) 的點我們就可以直接\(check\)了 \(.\)
那麼這個 \(case\) 也被我們解決了 \(.\)
//這個case程式碼量較大,不適合貼在部落格裡,但是評測連結裡有程式碼
\(solutions\) \(for\) \(Day4\)
\(D4T1\)
$description : $ 目前只有\(atcoder\)上有\(,\) \(loj/uoj\) 上都沒有 \(,\) 就不掛連結了
$solution : $
一種十分暴力但是非常難寫的做法
我們考慮對於每種顏色強行求出如果要包含它\(,\)需要的顏色種類有多少種\(.\)
對每種顏色建出虛樹\(.\)然後如果顏色\(c\)包含了虛樹上的一個點\(,\)那麼就向那個點所在的顏色連邊\(.\)
最後\(,\)如果顏色\(u\)在圖上能走到另一個顏色\(v,\)說明顏色\(u\)需要包含的顏色集合中有\(v.\) 那麼我們只要求出縮點之後的圖就可以解決問題了\(.\)
現在我們有\(O(n)\)個 一個點 往 樹上的一條鏈 連邊的操作\(.\)考慮優化建圖\(.\)
樹剖\(,\) \(st\) 表優化建圖 \(,\) 最後 \(tarjan\) 縮點解決\(.\)
時空複雜度為\(O(nlogn),\)程式碼長度很長 \((\) \(5\) 個 \(K\) \()\) \(,\) 空間很緊\(.\)
一種簡易方便的做法
咕咕咕