Try   HackMD

第六屆簡單的小競賽題解

我會按照我覺得的難度由簡單到困難排序。

pG. Waimai 超人與 Hehe 遊俠 (Easy Version)

我們可以將連續的

1 分成很多區間,可以知道一個長度為
k
的區間最多可以使用
k2
個。
於是最後可以
O(n)
算出來。

pD. 【…】,窩的超人

要如何加入字元才能使最終結果最大呢?有一個想法是把

1 通通加在左邊,把
0
通通加在右邊,應該很容易就能知道它是最大的,於是可以
O(n+m)
做出來。

pJ. 給測驗們的電神

費氏數列

Fi=Fi1+Fi2,轉成矩陣表示可以寫成
[1110]
,用
[Fi1Fi2]
去乘可以得到
[FiFi1]

於是可以矩陣快速冪求出
Fa,Fb
,那
Fb
在指數的地方要對什麼取餘數呢?根據費馬小定理,可以知道若
a
不是質數
p
的倍數,那
ap11 (mod p)
,於是
Fb
p1
取餘數,
Fa
p
取餘數。

有一點要注意的是

Fa 取完餘數後有可能是
0
,需要特別判斷,只不過最小的
a
使
Fa0
109+8
,在這題的範圍之外。

時間複雜度為

O(t×(log(a)+log(b)))

pH. Waimai 超人與 Hehe 遊俠 (Hard Version)

看到這一題有修改又有區間查詢,就會很想用線段樹,那要如何設計線段樹的節點內容呢,我們可以用

sum 表示這個節點最多幾人能使用,
lcnt
代表與節點最左邊相連,有幾個連續的馬桶,
rcnt
代表與節點最右邊相連,有幾個連續的馬桶。

sum 的更新方法就是左子節點的
sum +
右子節點的
sum
,然後中間的相連的部分要合併,於是可以扣掉左子節點的
rcnt2
與右子節點的
lcnt2
,再加上
nl.rcnt+nr.lcnt2

lcnt
rcnt
的更新方法就是若左子節點的
lcnt=
左子節點的長度,那就將
lcnt
設成
nl.lcnt+nr.lcnt
,否則設成
nl.lcnt
rcnt
同理。

最後總時間複雜度

O(n+q×log(n))

pC. 青蛙

如果沒有移動區間的操作,那用線段樹就可以了,那如果要移動區間呢?可以用一個叫做樹堆 (

Treap) 的東西,它可以
Merge
Split
區間,總時間複雜度
O(n×log(n))

pA. 揩淯愛牌組

可以知道,牌的順序其實不重要,我們只要知道每一種牌有幾張就好了,假設有

m 種牌,每種牌有
cnt[i]
張,我們可以用
dp
找出答案。

dp[i][j] 代表到了第
i
種牌,拿了
j
張,那
dp[i][j]=dp[i1][j]+cnt[i]×dp[i1][j1]
,答案就是
dp[m][k]

總時間複雜度為

O(n×(log(n)+k)),如果用滾動
dp
可以減少記憶體。

hehe

這題有一個很陰險的地方就是模的是

998244853

pI. 確實大師 (Chesh Master)

現在先假設要求的是二維的,那距離有哪些表示法呢?有

(xixj)2+(yiyj)2,|xixj|+|yiyj|,max(|xixj|,|yiyj|),前兩個都很難用在此題,但第三個只要找到兩邊的最大跟最小相減,然後取
max
就好了。

我們要如何將

|xixj|+|yiyj| 轉到
max(|xixj|,|yiyj|)
呢? 可以令新的
x
座標變成
xi+yi
y
座標變成
xiyi
,那後面的式子就會等於原本前面的。

那三維的要如何轉換,可以用一個四維的

(x,y,z,w) 表示,
x=xi+yi+zi
y=xi+yizi
z=xiyi+zi
w=xiyizi
,這樣就可以用
4
multiset
,每次回答
4
multiset
裡最大值與最小值的差的最大值,並且可以
O(log(n))
加入與刪除數字。

總時間複雜度

O(n×log(n))

pB. 電橘子與電耗子

可以觀察到如果一個耐電值

X 可以成功融合,那比
X
大的都可以融合;如果一個耐電值
X
無法成功融合,那比
X
小的都無法成功融合。

於是我們可以二分搜答案,那有了給定的

X,要如何判斷呢?我們可以先計算出
ai
bj
的發電值,如果小於等於
X
就建邊。因為我們想要把全部都配在一起,所以可以做二分圖最大匹配,如果匹配數是
n
,就代表成功了。

總時間複雜度

O(n3×log(C)),如果用一些特別的作法說不定可以更好?

pF. 嗯呀喜歡這個

最短距離

vi 可以用
dijkstra
O(n×log(n))
算出來。

剩下的就是如何挑選

a 個和
b
個節點了,我們令
ui=di×vi+ci
,然後將
(vi,ui)
由大排到小。最後會選
ab
vi
b
ui
,假設選的
vi
裡面,編號最大的是
x
,那可以知道
x
之前的都會被選到,因為如果有沒被選到的,假設編號是
y
,那就不要選
vx
,改選
vy
就好了 (因為
vi
遞減,
vyvx
)。那就可以
abia
1i
都有被選到,再從
ni
個剩下的找答案。

總時間複雜度

O(n×log(n))

pE. 磚牆改

這題叫做磚牆改是因為是從

IOI 2014 Wall 改編過來的,只是這題沒有取
min
操作,是因為會跟等一下要講的東西有關。

如果是單純的詢問、操作,那就用線段樹就可以了,每個節點可以設一個

mx
mn
,代表此節點涵蓋的區間裡的最大值與最小值,而
push
pull
的方法需要好好想一下。

push 的方法為:

node[lpos].mx = max (node[lpos].mx, node[pos].mn); node[lpos].mx = min (node[lpos].mx, node[pos].mx); node[rpos].mx = max (node[rpos].mx, node[pos].mn); node[rpos].mx = min (node[rpos].mx, node[pos].mx); node[lpos].mn = min (node[lpos].mn, node[pos].mx); node[lpos].mn = max (node[lpos].mn, node[pos].mn); node[rpos].mn = min (node[rpos].mn, node[pos].mx); node[rpos].mn = max (node[rpos].mn, node[pos].mn);

pull 的方法為:

node[pos].mx = max (node[lpos].mx, node[rpos].mx); node[pos].mn = min (node[lpos].mn, node[rpos].mn);

那有了刪除操作要怎麼做呢?可以觀察到對區間

[l1,r1]
max
,再對區間
[l2,r2]
max
,順序其實沒差,並且我們做了一個操作後,只要把變化前的值記錄下來,就可以還原。所以就能想到可以用時間線段樹,進入一個節點時執行操作,出去節點時還原操作,就能
AC
了!

總時間複雜度

O(q×log(q)×log(n))

心得

大家都好厲害