分享到plurk 分享到twitter 分享到facebook

[UVa] 10408

網址

http://uva.onlinejudge.org/external/104/10408.html

題目概述

求出 Farey sequences 的第 k 個數字

Farey sequences ( n = 5 ): 1/5, 1/4, 1/3, 2/5, … , 1/1

分子 = x, 分母 = y

x <= y

x/y 由小到大 value 不重複排序

Technique details

1 <= n <= 1000

k 在合理範圍

輸入格式

每一行是一組測資 : n, k

輸出格式

每一行是一組測資輸出 : Farey sequences 的第 k 個數字

解題思路

解法一、時間複雜度 ( O(KlogN) )

運用 priority_queue ( min heap)

一開始先建立 1/n, 1/n-1, … 1/1

之後每次 pop 最小的 x/y

push (x+1)/y

pop 到第 k 個就是答案

想法簡單,但是要小心幾個地方:

  1. 雖然 2/4 = 1/2, 但是 2/4 也要 push 進去,不然之後會漏掉 3/4

  2. 每次 pop x/y 之後,就要去檢查 visit [ x / gcd(x,y) ] [ y / gcd(x,y) ] 是否出現過,

若有 k 要 +1 ,因為已計算過 (ex: 1/2, 2/4 只算一次)

若沒出現過則記錄 visit [ x / gcd(x,y) ] [ y / gcd(x,y) ] = true

解法二、時間複雜度 ( O(K) )

給一個 N = 5 的例子 ( 下面都會以這個例子解釋 )

令 1/4 = prevx/prevy,

1/3 = x/y,

2/5 = nextx/nexty

代表任 3 個連續的數列

Farey sequences 有一個特性: prevy * x - prevx * y = 1

那要怎麼運用這個特性求出 nextx / nexty 呢?

我們可以觀察到另一個等式,會符合上面的特性

nextx = x * k - prevx // 2 = 1 * 3 - 1

nexty = y * k - prevx // 5 = 3 * 3 - 4

k 可以是任何整數

但是 Farey sequences 是 x/y 小者為優先

所以要讓 k 越大越好,而且算出來的 nextx / nexty 是在合理的範圍內

因為分母一定比分子大,所以算 k 只要看分母就好

因為 y * k - prevy <= N //nexty不可以超過 N

所以 k = ( prevy + N ) / y

例如:( 4 + 5 ) / 3 = 3

知道了 k 和 nextx, nexty 的算法,就可以求出整個數列。