IOI2021 Day2 簡要題解

從七點半做到五點,我裂開了。

主要原因是 T2 暴露出我完全沒有代碼能力、 T3 暴露出我不會小學數學。

T2 的 sb 錯誤包括但不限於

  • 定義的變量忘記預處理。
  • MLE 。
  • 樹上單調棧寫掛。

T3 的 sb 錯誤包括但不限於

  • 20*20=4000 。
  • 寫了 cnt+=2 之後誤以爲自己寫的是 cnt++ ,於是誤以爲自己要大約 5000 次操作。

T1

\(s_i\)\(t_i\) 連一條邊,得到一個 3 個點、若干條邊的圖。

一次操作就是交換兩條邊的起點。

隨便貪心即可。正確性看着就很沒問題。

https://loj.ac/s/1167042

T2

無腦的想法就是把每一種基環樹都預處理出來,然後詢問的時候暴力跳,直到超過下一個人。但是這種想法沒有前途。

嘗試分析跳躍的性質,發現沒有性質。

觀察收益。輸了的時候收益可能很小,但是贏的收益是其能力值,看起來會比較大。

如果有一個人我現在打不過,但是過了若干次之後把他打敗了,那麼我的能力值此時至少乘了 2 。

但是下一個現在打不過而以後打得過的人也不好找。

但是我們主要的目標是讓自己的能力值乘 2 ,所以可以把 \((2^i,2^{i+1}]\) 能力值的人分成一組,每次只要找到一個打得過的組別夠大的人即可。

這樣只有 \(\log w\) 個基環樹。亂搞搞可以做到 \(O((n+q)\log n\log w)\) 。然而寫完就會發現跑不過去。

考慮把乘 2 變成乘 \(k\) ,那麼複雜度就是 \(O(n\log_k w\log n+qk\log_k w\log n)\) 。取 \(k=8\) 即可獲得 \(1\over 3\) 的常數。

loj 不太喜歡我的代碼,但是在 oj.uz 過了。

https://oj.uz/submission/438455

T3

先考慮怎麼比較兩個數 \(x,y\) 的大小。

\(b>k\) ,所以假裝我們在模 \(2^{k+1}\) 意義下做加法。那麼把 \(y\) 按位取反(下面稱爲 \(rev(y)\) ),加上 \(x\) ,即得到 \(x-y-1\) 。觀察第 \(k\) 位是 0 還是 1 即可。

爲了把最小值取出來,需要 \(2\log k\) 的次數把第 \(k\) 位擴展到所有 \(k+1\) 位,然後和 \(x\) 取 and 。

但是這樣一次差不多需要 20 次操作,非常爆炸。

因爲 \(b=2000>nk\) ,所以考慮一次多進行一些操作。假設 \(X,Y\) 分別是 \(n/2\) 個數連在一起,我們需要分別求 \(\min\) ,然後把 \(\min\) 放在 \(X\) 的位置。

問題 1 :數連在一起,所以“第 \(k\) 位”會是下一個數的第 0 位。

解決方案:無所謂。只需要 \(X+rev(Y)\) 的時候“第 \(k\) 位”恰好有一個 0 一個 1 ,就不會有什麼問題。給 \(X+rev(Y)\) 異或上 \(X\oplus Y\) 即可。

問題 2 :下面的數加在一起的時候可能會給上面的數進位。

解決方案:同樣無所謂。\(x-y-1\)\(x-y\) 幾乎沒有區別。

這樣我們就可以用大約 20 次操作把 \(n\) 個數折半。所以第一問就用 \(20\log n\) 次操作做完了。

我們現在有一個大約 20 次操作可以比較 199 個數的神奇黑箱,考慮找一個和這比較契合的排序方法。

思來想去發現沒啥好用的,那就自己編。

// 我稱之爲 冒泡排序-plus
rep(k,1,(n+1)/2)
{
	for (int i=1;i<n;i+=2) if (a[i]>a[i+1]) swap(a[i],a[i+1]);
	for (int i=2;i<n;i+=2) if (a[i]>a[i+1]) swap(a[i],a[i+1]);
}

不太清楚爲什麼這個能夠完成排序任務,但它確實完成了。

那麼就只需要調用 \(n\) 次黑箱就做完了。

https://loj.ac/s/1167378

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