• 沒有找到結果。

根號算法

N/A
N/A
Protected

Academic year: 2022

Share "根號算法"

Copied!
69
0
0

加載中.... (立即查看全文)

全文

(1)

根號算法

by nkhg (t1016d)

(2)

RMQ(Range minimum query)

• 給你一個長度 N 的序列 A[0], A[2], ..., A[N - 1]

• 緊接著 Q 筆詢問,每筆詢問是一個數對 x, y

• 請你回答 min{ A[x], A[x + 1], ..., A[y] }

• A = {5, 2, 8, 1, 7}

• Query = {(0, 2), (1, 4), (2, 2)}

• 答案:2 1 8

(3)

RMQ(Range minimum query)

• 時間複雜度 O(QN)

• 特性:min(a, b, c) = min(a, min(b, c))

• 可以對一部分數字先求最小值,再從每個部份的最小值中取最小 的!

(4)

RMQ(Range minimum query)

• 一部分?

• 每連續 k 個分一組,先把每組的最小值算好並存下來

• 對於詢問

• 綠色每塊都先算好了,時間花費是塊數:最多 N/k

• 紅色部份每個數字跑一遍,時間花費是一塊大小:最多 2k

(5)

RMQ(Range minimum query)

• 每次詢問 O(N/k + k) 取個好的 k?

• 算幾不等式:N/k + k <= 2*sqrt(N/k * k) = 2*sqrt(N)

• 在 N/k = k 也就是 k = sqrt(N) 時最小

• 所以取 k 為 sqrt(N) 就有了每次詢問 O(sqrt(N)) 的解法 了

• 預處理 O(N)

(6)

RMQ(Range minimum query)

• 於是大家獲得了人生第一個根號算法 (?)

• RMQ 是很經典的問題

• 線段樹:預處理 O(N) - 詢問 O(log N)

sparse table:預處理 O(N log N) - 詢問 O(1)

• 線性 RMQ:預處理 O(N) - 詢問 O(1)

• 資芽只會教到線段樹

(7)

實作上

(8)

中國人插隊問題

• 一開始給一個長度 N 的序列(index 1 到 N)

• 接著 Q 次操作,每次可能是

a. 請在第 i 個位子插入數字 x(index >= i 的數字往後一格)

b. 拔掉第 i 個位子的數字(index > i 的數字往前一格)

c. 請你回答第 i 個位子的數字是多少

• 例如

• 初始:1, 2, 3, 4, 5

• 操作:(a, 1, 6), (a, 7, 7), (c, 4), (b, 3), (b, 3), (c, 5)

• 過程:

6, 1, 2, 3, 4, 5

6, 1, 2, 3, 4, 5, 7 (輸出 3)

6, 1, 3, 4, 5, 7

6, 1, 4, 5, 7 (輸出 7)

(9)

中國人插隊問題

• 天上傳來一道聲音,叫你再試試看剛剛那樣「分塊」

(10)

中國人插隊問題

• 嘗試讓每塊儲存了 K 個數字 (若 K = 4)

A1 A2 A3 A4

A5 A6 A7 A8

A9 Aa Ab Ac

1

2

3

(11)

中國人插隊問題

• 一開始給一個長度 N 的序列(index 1 到 N)

• 接著 Q 次操作,每次可能是

a. 請在第 i 個位子插入數字 x(index >= i 的數字往後一格)

b. 拔掉第 i 個位子的數字(index > i 的數字往前一格)

c. 請你回答第 i 個位子的數字是多少

• 例如

• 初始:1, 2, 3, 4, 5

• 操作:(a, 1, 6), (a, 7, 7), (c, 4), (b, 3), (b, 3), (c, 5)

• 過程:

6, 1, 2, 3, 4, 5

6, 1, 2, 3, 4, 5, 7 (輸出 3)

6, 1, 3, 4, 5, 7

6, 1, 4, 5, 7 (輸出 7)

(12)

中國人插隊問題

• 增加一個數字(第 3 個位置插入 B)

A1 A2 A3 A4

A5 A6 A7 A8

A9 Aa Ab Ac

1

2

3

(13)

中國人插隊問題

• 增加一個數字(第 3 個位置插入 B)

A1 A2 A3 A4

A5 A6 A7 A8

A9 Aa Ab Ac

1

2

3

(14)

中國人插隊問題

• 增加一個數字(第 3 個位置插入 B)

A1 A2 A3 A4

A5 A6 A7 A8

A9 Aa Ab Ac

1

2

3

B

(15)

中國人插隊問題

• 增加一個數字(第 3 個位置插入 B)

A1 A2 A3 A4

A5 A6 A7 A8

A9 Aa Ab Ac

1

2

3

B

(16)

中國人插隊問題

• 增加一個數字(第 3 個位置插入 B)

A1 A2 A3

A4 A5 A6 A7 A8

A9 Aa Ab Ac

1

2

3

B

(17)

中國人插隊問題

• 增加一個數字(第 3 個位置插入 B)

A1 A2 A3

A4 A5 A6 A7 A8

A9 Aa Ab Ac

1

2

3

B

(18)

中國人插隊問題

• 增加一個數字(第 3 個位置插入 B)

A1 A2 A3

A4 A5 A6 A7

1

2

3

B

A8 A9 Aa Ab Ac

(19)

中國人插隊問題

• 增加一個數字(第 3 個位置插入 B)

A1 A2 A3

A4 A5 A6 A7

1

2

3

B

A8 A9 Aa Ab

4 Ac

(20)

中國人插隊問題

• 一開始給一個長度 N 的序列(index 1 到 N)

• 接著 Q 次操作,每次可能是

a. 請在第 i 個位子插入數字 x(index >= i 的數字往後一格)

b. 拔掉第 i 個位子的數字(index > i 的數字往前一格)

c. 請你回答第 i 個位子的數字是多少

• 例如

• 初始:1, 2, 3, 4, 5

• 操作:(a, 1, 6), (a, 7, 7), (c, 4), (b, 3), (b, 3), (c, 5)

• 過程:

6, 1, 2, 3, 4, 5

6, 1, 2, 3, 4, 5, 7 (輸出 3)

6, 1, 3, 4, 5, 7

6, 1, 4, 5, 7 (輸出 7)

(21)

中國人插隊問題

• 拔掉一個數字(拔掉第 3 個位置)

A1 A2 A3 A4

A5 A6 A7 A8

A9 Aa Ab Ac

1

2

3

(22)

中國人插隊問題

• 拔掉一個數字(拔掉第 3 個位置)

A1 A2 A4

A5 A6 A7 A8

A9 Aa Ab Ac

1

2

3

(23)

中國人插隊問題

• 拔掉一個數字(拔掉第 3 個位置)

A1 A2 A4

A5 A6 A7 A8

A9 Aa Ab Ac

1

2

3

(24)

中國人插隊問題

• 拔掉一個數字(拔掉第 3 個位置)

A1 A2 A4 A5

A6 A7 A8

A9 Aa Ab Ac

1

2

3

(25)

中國人插隊問題

• 拔掉一個數字(拔掉第 3 個位置)

A1 A2 A4 A5

A6 A7 A8

A9 Aa Ab Ac

1

2

3

(26)

中國人插隊問題

• 拔掉一個數字(拔掉第 3 個位置)

A1 A2 A4 A5

A6 A7 A8 A9

Aa Ab Ac

1

2

3

(27)

中國人插隊問題

• 拔掉一個數字(拔掉第 3 個位置)

A1 A2 A4 A5

A6 A7 A8 A9

Aa Ab Ac

1

2

3

(28)

中國人插隊問題

• 一開始給一個長度 N 的序列(index 1 到 N)

• 接著 Q 次操作,每次可能是

a. 請在第 i 個位子插入數字 x(index >= i 的數字往後一格)

b. 拔掉第 i 個位子的數字(index > i 的數字往前一格)

c. 請你回答第 i 個位子的數字是多少

• 例如

• 初始:1, 2, 3, 4, 5

• 操作:(a, 1, 6), (a, 7, 7), (c, 4), (b, 3), (b, 3), (c, 5)

• 過程:

6, 1, 2, 3, 4, 5

6, 1, 2, 3, 4, 5, 7 (輸出 3)

6, 1, 3, 4, 5, 7

6, 1, 4, 5, 7 (輸出 7)

(29)

中國人插隊問題

• 第 i 個數字:第 _______________ 塊的第 ___________ 個

A1 A2 A3 A4

A5 A6 A7 A8

A9 Aa Ab Ac

1

2

3

(30)

中國人插隊問題

• 第 i 個數字:第 (i - 1) / K + 1 塊的第 (i - 1) % K 個

A1 A2 A3 A4

A5 A6 A7 A8

A9 Aa Ab Ac

1

2

3

(31)

中國人插隊問題

• 如果有一個可以 O(1) 從頭尾兩端刪除或增加的資料結構來維 護每一塊的話

(內部的查找、刪除都是與儲存的大小成線性)

• 插入:該塊內部 O(K)、之後每塊都要修一下 O(N / K)

• 刪除:該塊內部 O(K)、之後每塊都要修一下 O(N / K)

• 詢問:該塊內部 O(K)

• 找到第 i 塊?

• 把一堆這種資料結構開成陣列:O(1)

• 把一堆這種資料結構串起來(linked list):O(N / K)

• 總之全部合起來就是 O(K + N / K) => 又是根號了!

(32)

中國人插隊問題

如果

有一個可以 O(1) 從頭尾兩端刪除或增加的資料結構來 維護每一塊的話

(內部的查找、刪除都是與儲存的大小成線性)

• 方法很多,例如 雙向鏈結串列(Doubly linked list)

(33)

在線與離線

對於剛剛兩題這種有多個詢問、操作的題目

• 在線 (online):程式/演算法 必須對前一個詢問或操作做出 回答,之後才能知道下一個詢問或操作。

(換句話說就是寫程式讀了一行就要馬上處理它)

• 離線 (offline):程式/演算法 不須先對前一個詢問或操作 做出回答,就能知道下一個詢問或操作

(換句話說你的程式可以先把全部輸入讀進來再來想辦法)

(34)

在線與離線

• 為什麼要區分在線與離線呢?

• 哪一個比較簡單?

(35)

在線與離線

(36)

在線與離線

• 將來有很多離線比較簡單的例子在等著大家 A_A

(37)

Counting Triangles

• 給你一個 N 個點、M 條邊的簡單無向圖,請算出這張圖裡有幾 個「三角形」?

• 假設點被編號為 0 到 N - 1,三角形定義為一組數對 (x, y, z) 使得 0 <= x < y < z < N 且

(x, y)、(y, z)、(z, x) 均有邊

• 3 <= N <= 10^5

• 0 <= M <= 10^5

(38)

Counting Triangles

• 假設我們能夠 O(1) 回答某個給定的 pair (x, y) 是否為圖上的一條邊

• 那麼指定任一個點 v,我們能夠

a. 在 O(M) 時間內算出圖中有幾個包含 v 的三角形 b. 在 O(d^2) 時間內算出圖中有幾個包含 v 的三角形

(其中 d 為 v 的點度)

• 每個三角形包含恰 3 個點,

所以對所有點算出「包含它的三角形個數」加總除以 3,

就是答案了!

(39)

Counting Triangles

• 假設我們能夠 O(1) 回答某個給定的 pair (x, y) 是否為圖上的一條邊

• 按照點度是否大於 K 分兩條

• 大於 K 的: 作法 a. (O(M))

• 不超過 K 的:作法 b. (O(d^2))

(40)

Counting Triangles

• 假設我們能夠 O(1) 回答某個給定的 pair (x, y) 是否為圖上的一條邊

• 按照點度是否大於 K 分兩條

• 大於 K 的: 作法 a. (O(M))

• 這種點不超過 2M / K 個,總共 O(M^2 / K)

• 不超過 K 的:作法 b. (O(d^2))

• 這種點最多 N 個,每個 d 最大到 K,總共 O(N * K^2)

(41)

Counting Triangles

• 假設我們能夠 O(1) 回答某個給定的 pair (x, y) 是否為圖上的一條邊

• 按照點度是否大於 K 分兩條

• 大於 K 的: 作法 a. (O(M))

• 這種點不超過 2M / K 個,總共 O(M^2 / K)

• 不超過 K 的:作法 b. (O(d^2))

• 這種點最多 N 個,每個 d 最大到 K,總共 O(N * K^2)

(42)

Counting Triangles

• 假設我們能夠 O(1) 回答某個給定的 pair (x, y) 是否為圖上的一條邊

• 按照點度是否大於 K 分兩條

O(M^2 / K + MK)

• 又是算幾砸下去,取 K = sqrt(M)

• 得到 O(M sqrt(M))

• 於是這題被完美的解決了(?)

(43)

Counting Triangles

假設

我們能夠 O(1) 回答某個給定的 pair (x, y) 是否為圖上的一條邊

• 那麼指定任一個點 v,我們能夠

a. 在 O(M) 時間內算出圖中有幾個包含 v 的三角形

b. 在 O(d^2) 時間內算出圖中有幾個包含 v 的三角形

(其中 d 為 v 的點度)

(44)

Counting Triangles

假設

我們能夠 O(1) 回答某個給定的 pair (x, y) 是否為圖上的一條邊

• 那麼指定任一個點 v,我們能夠

a. 在 O(M) 時間內算出圖中有幾個包含 v 的三角形

• 開一條 bool 陣列 adj,adj[i] 表示 v 與 i 之間是否有邊

b. 在 O(d^2) 時間內算出圖中有幾個包含 v 的三角形

(其中 d 為 v 的點度)

(45)

Counting Triangles

假設

我們能夠 O(1) 回答某個給定的 pair (x, y) 是否為圖上的一條邊

• 那麼指定任一個點 v,我們能夠

a. 在 O(M) 時間內算出圖中有幾個包含 v 的三角形

• 開一條 bool 陣列 adj,adj[i] 表示 v 與 i 之間是否有邊

b. 在 O(d^2) 時間內算出圖中有幾個包含 v 的三角形

(其中 d 為 v 的點度)

• 我們只在乎這邊給出的所有 (x, y) 詢問總共有幾個為 true

而且照 a. 的作法,只要一堆連續的詢問有共同端點我們就會做了

(46)

Counting Triangles

假設

我們能夠 O(1) 回答某個給定的 pair (x, y) 是否為圖上的一條邊

• 那麼指定任一個點 v,我們能夠

a. 在 O(M) 時間內算出圖中有幾個包含 v 的三角形

• 開一條 bool 陣列 adj,adj[i] 表示 v 與 i 之間是否有邊

b. 在 O(d^2) 時間內算出圖中有幾個包含 v 的三角形

(其中 d 為 v 的點度)

• 我們只在乎這邊給出的所有 (x, y) 詢問總共有幾個為 true

而且照 a. 的作法,只要一堆連續的詢問有共同端點我們就會做了

離線!

把全部詢問照端點分類存起來最後再做

(47)

Counting Triangles

• 開一條 bool 陣列 adj,adj[i] 表示 v 與 i 之間是否有邊 這條陣列怎麼寫?

(48)

Counting Triangles

• 開一條 bool 陣列 adj,adj[i] 表示 v 與 i 之間是否有邊 這條陣列怎麼寫?

(49)

Counting Triangles

• 開一條 bool 陣列 adj,adj[i] 表示 v 與 i 之間是否有邊 這條陣列怎麼寫?

(50)

Counting Triangles

• 另一個結論可能比較簡潔但思路似乎沒那麼自然的作法

(不過它或許會給大家一些啟示)

• 對於一條邊 (u, v),我們可以用 O(max(d_u, d_v)) 算出包含這條 邊的三角形個數(d_u, d_v 是 u 和 v 的點度)

• 只要一開始把每個點的相鄰點排序過

• 如果 (u, v) 中點度較大的那個點,我們有它的相鄰矩陣,那麼同一件 事可以做到 O(min(d_u, d_v))

(51)

Counting Triangles

• 把點度 >= sqrt(M) 的點叫做「重點」,其他叫「輕點」

• 重點只有 2*sqrt(M) 個

• 所以把「重點」對所有點的相鄰矩陣建出來

• 空間也只要 O(N sqrt(M))

• 對所有邊計算它被幾個三角形包含

• 輕點-輕點:用 O(max(d_u, d_v)) 的作法,也才 O(sqrt(M))

• 輕點-重點:用 O(min(d_u, d_v)) 的作法,也才 O(sqrt(M))

• 重點-重點:用 O(min(d_u, d_v)) 的作法,也才 ...?

(52)

Counting Triangles

• 對一個重點 u,如果計算某條邊 (u, v) 的 cost O(min(d_u, d_v)) 是 d_u

表示這條邊連接的點 v 具有 d_v > d_u

這種點 v 最多只有 2M / d_u 個

所以以 d_u 為 cost 的邊的花費加總起來也才

(2M / d_u) * d_u = 2M = O(M)

• 重點只有 O(sqrt(M)) 個,它們的總花費就是 O(M sqrt(M))

• 三種情況都在 O(M sqrt(M)) 內,解決!

(53)

Counting Triangles

• 把點度 >= sqrt(M) 的點叫做「重點」,其他叫「輕點」

• 重點只有 2*sqrt(M) 個

• 所以把「重點」對所有點的相鄰矩陣建出來

• 空間也只要 O(N sqrt(M))

• 對所有邊計算它被幾個三角形包含

• 輕點-輕點:用 O(max(d_u, d_v)) 的作法,也才 O(sqrt(M))

• 輕點-重點:用 O(max(d_u, d_v)) 的作法,也才 O(sqrt(M))

• 重點-重點:用 O(min(d_u, d_v)) 的作法,也才 ...?

(54)

Counting Triangles

(55)

Counting Triangles

• 把點度 >= sqrt(M) 的點叫做「重點」,其他叫「輕點」

• 重點只有 2*sqrt(M) 個

• 所以把「重點」對所有點的相鄰矩陣建出來

• 空間也只要 O(N sqrt(M))

• 對所有邊計算它被幾個三角形包含

• 輕點-輕點:用 O(max(d_u, d_v)) 的作法,也才 O(sqrt(M))

• 輕點-重點:用 O(min(d_u, d_v)) 的作法,也才 O(sqrt(M))

• 重點-重點:用 O(max(d_u, d_v)) 的作法,也才 ...?

(56)

Counting Triangles

(57)

Counting Triangles

• 重點整理與啟發

第一種作法枚舉點、第二種作法枚舉邊

找出枚舉後的複雜度關鍵是什麼,對那個東西分大小

• 第一種作法用到的技巧

離線

可重複利用並快速歸零的 bool array

• 第二種作法用到的技巧

「重點」很少,可以維護一個「重點」X「所有點」的二維陣列

• 小心估複雜度

(58)
(59)

邪惡收集大作戰

• 你有 N 個物品,每個物品都有它的邪惡值 A_i

• 請你從這 N 個物品中挑一些,使得邪惡值總和為 K

• N <= 40

• K、每個 A_i、A_i 的總和都在 [1, 10^18]

(60)

邪惡收集大作戰

• 我會做 2^N

• 2^40 大約是 10^12

(61)

邪惡收集大作戰

• 如果我們可以把問題分割成「規模相近」的兩部分

• 而且可以用「好方法」把問題的兩個部分合併

• 那就有機會藉此減少時間複雜度!

• 40個物品…任意分割成兩個大小類似的集合

(62)

邪惡收集大作戰

3 7 12 5 1 4

• 左半邊可以組合出什麼組合呢

• {}、{3}、{7}、{12}、{3,7}、{3,12}、{7,12}、{3,7,12}

• 總和分別為 {0,3,7,12,10,15,19,33}

• 那麼, 右半邊呢

• {}、{5}、{1}、{4}、{5,1}、{1,4}、{5,4}、{5,1,4}

• 總和分別為 {0,5,1,4,6,5,9,10}

(63)

邪惡收集大作戰

• 如果我們想要湊出總和為 K

• 左半邊總和分別為 {0,3,7,12,10,15,19,33}

• 右半邊總和分別為 {0,5,1,4,6,5,9,10}

• 如果左邊所取的物品,價值總和為 i

• 右邊就必須拿到 M-i

(64)

邪惡收集大作戰

• 分別考慮左邊的所有物品能湊出的價值

• 分別考慮右邊的所有物品能湊出的價值

• 需要多少時間? 分別需要 O(2^(N/2))

• 我們總共想要價值M

• 枚舉左邊集合的所有價值 i

• 如果在右邊找的到 M-i,那就成功了

• 如果右邊找不到M-i呢? 那就表示不存在「從左邊集合取出總和 i, 右邊集合取出總和 M-i 的方法」

(65)

邪惡收集大作戰

• 如何從右邊的集合中尋找 M-i 呢?

• 先排序! 再搜尋

• 每一個 O(log(2^(N/2)))

• O(2^20 * log2 (2^20)) -> 2 * 10^7

• 雖然不太爽,但至少比原先的 O(2^40) 快多了

(66)

邪惡收集大作戰

• 要如何找出一組可行的方案?

• Struct XDDD {

• long long sum; //儲存總和

• bool used[N]; //紀錄每個元素是否用到

• }

(67)

邪惡收集大作戰

• Struct XDDD { //照sum排序

• long long sum; //儲存總和

• int used; //紀錄每個元素是否用到,用一個int就過了

• }

• 因為搜索的問題本身規模不會太大

• 位元運算是方便好寫的好選擇

• 很快,很節省空間

(68)

題目

https://oj.icpc.tw/c/28/D (緊接著有飲料盃)

• 給你一個 N 個點、M 條邊的簡單無向圖

• Q 筆詢問,每筆詢問輸入一個環,請計算這個環有幾個「弦」

• N, M, 每個詢問的環大小總和 <= 3 * 10^5

(69)

題目

SRM 675 Div.1 Middle

• 給你 n, x0, a, b,表示有一個長度 n 的數列:

x[0] = x0

for (int i = 1; i < n; i++)

x[i] = (x[i - 1] * a + b) % (10^9 + 7)

• 你要回答 Q 個詢問,每個詢問給你一個 k (0 <= k < n),

請你回答數列 x 中第 k 小的數字(k=0 為最小)

• n <= 5 * 10^6

• Q <= 100

• 時限 10sec、額外儲存空間限制 1MB

參考文獻

相關文件

在選擇合 適的策略 解決 數學問題 時,能與 別人溝通 、磋商及 作出 協調(例 如在解決 幾何問題 時在演繹 法或 分析法之 間進行選 擇,以及 與小組成 員商 討統計研

• 我們通常用 nD/mD 來表示一個狀態 O(N^n) ,轉移 O(N^m) 的 dp 演算法. • 在做每題

•  問你當前的序列裡的第 k個人是誰 (區間詢問?). • 

•  問你當前的序列裡的第 k個人是誰 (區間詢問?). • 

將繩子折成相等的四小段,已知每一小段都是 x 公分,. 已知繩子的全長為

 點擊按鈕「Rollover」,工作表便會剪下紅色線以下的資料並複 製至綠色線以下的儲存格。

• 在線 (online):程式/演算法 必須對前一個詢問或操作做出

RMQ(Range minimum