今天的Farey竟然挂掉了,实在咽不下这口气,晚上又整理了一下资料。
以供大家一起学习。
Farey序列
Fn = {a/b | gcd(a,b)=1 && 0<=a,b<=n};
即由小于或等于n的整数所组成的不可再约分数的递增序列,并满足分子分母互质。
如:
F1 = {0/1, 1/1}
F2 = {0/1, 1/2, 1/1}
F3 = {0/1, 1/3, 1/2, 2/3, 1/1}
性质
除了F1,其余Farey序列都有奇数个元素,并且中间值是1/2。
Farey序列是一个对称序列,头尾之和为1。
假如序列中有三个连续元素x1/y1, x2/y2, x3/y3,则有x2 = x1+x3; y2 = y1+y3;
并且有x1*y2 – x2*y1 = 1。这条性质保证构造出来的分式肯定是不可约分式。
构造
从第三个性质我们可以得出它的构造方法。求N阶Farey序列:
Procedure make_farey(x1,y1,x2,y2 : integer)
If x1+x2>N or y1+y2>N then Return
make_farey(x1,y1,x1+x2,y1+y2)
inc(total)
farey [total] = {x1+x2,y1+y2}
make_farey(x1+x2,y1+y2,x2,y2)
End Procedure.
就这么简单,当时竟然没想到,唉。
这个方法适合随机给定N,求Farey序列。
如果求出连续的F1,F2,F3,F4…Fn的话,朴素构造方法更好。
Procedure make_farey(n : integer)
farey[1] = {0/1, 1/1}
total = 2
For i=2 to n
farey [i] = {0/1}
For j=2 to total
If farey [i-1][j].denominator + farey [i][j]. denominator = N then
farey[i] += { farey [i-1][j] + farey [i][j] }
End if
farey [i] += {farey [i-1][j]}
End for
End for
End Procedure.
当时思维局限在这个构造算法上,导致超时。
所谓的Stern-Brocot树,其实已经在第一个构造算法里面隐含了。
Stern-Brocot扩展了Farey序列,它能构造出小于某个分式的所有分式,当然这些分式是无穷的。所以它能从另一方面证明素数是无穷的。
查找第K大元素
今天pku 3374 Cake Share有较多查询,得预先构造出Fn序列。
如果查询对不可预知Fn的时候,我们可以简单的改造算法1,当total达到k时输出后,立即跳出。时间复杂度O(K)。K最大就是|Fn|。
Fn的序列大小是可以递推出来的,有一个近似公式,可以让我们大致了解下Fn的大小程度。
|Fn| = 0.304*N^2。如 |F5000| ≈ 7600000,实际有7600459个。
那可以看出这个算法复杂度是O(N^2)的。
黑书上的解决方案是二分加上统计。没有详细描述。
今天比赛时,想了一下,可以如下操作:
规定另一个操作计算出小于给定分式的不可约分式数目,要求<=O(NlogN)。
再对X/N的X进行二分枚举,找出区间X/N ~ (X+1)/N。
在枚举出改区间的所有不可约分式,最多也就N个。
统计再输出答案。
总过程时间复杂度是O(N (logN)^2)的。关键就在于实现O(NlogN)的操作。
比赛时一直想不通它的实现,以后有想法再说了。
推荐题目
PKU 2478 Farey Sequence
TJU 2798 Farey Sequence
PKU 3374 Cake Share


















































