法雷(法里)序列

定义:

  对任意给定的一个自然数n,将分母小于等于n的不可约的真分数按升序排列,并且在第一个分数之前加上0/1,在最后一个分数之后加上1/1,这个序列称为n级法雷数列,即法雷数列是0和1之间最简分数升序排列的数列,所以n级法雷数列的个数即为 满足 1 <= a < b <= n && gcd( a , b ) == 1 的二元组( a , b )的数量 + 2(0/1 和 1/1)

性质:

  1. 除了1级法雷数列外,所有的法雷数列都有奇数个元素,其中居于正中间的那个元素一定是1/2.
  2. n级法雷数列中,若相邻两个元素是 a / b 和 c / d ( a / b < c / d ),则这两个数的差为1 / bd, 这个差的最小值为1/(n*(n-1)), 最大值为1/n,,在法雷数列的第一个元素(0/1)与其后继以及最后一个元素(1/1)与前驱之间的差取到最大值,而正中间的那个元素1/2 与其前驱和后继元素之间的差取次大值1/(n*2).
  3. 任意两个相邻元素 a / b 和 c / d   ( a / b < c / d ),满足 b * c - a * d == 1
  4. 任意三个相邻元素,中间元素 == (前驱元素分子 + 后继元素分子)/(前驱元素分母 + 后继元素分母)
  5. 设F(n)为第n级法雷数列的个数,phi(n)为欧拉函数的值,则F( n ) = F( n-1 ) + phi( n )   ( 考虑法雷序列定义 ,正确性显然)
  6. 当n趋于正无穷时,n级法雷数列包含的元素的个数趋于 3 * n * n / ( pi * pi )    ( pi = acos(-1) )

构造:

  根据性质4即可简单构造,Stern-Brocot树是一种数据结构,能构造法雷数列。Stern-Brocot树是从0 (= 01)和1 (= 11)开始,取中间分数来构成法里数列,即根据性质4构造。

Stern-Brocot树生成规则:

HDU4556 Stern-Brocot Tree

上图是一棵Stern-Brocot树,其生成规则如下:
  从第1行到第n行,每行相邻两数a/b和c/d,产生中间数(a+c)/(b+d),置于下一行中。将一行的分数(包括0/1,1/0),进行约分简化,则每一行(包括0/1,1/0,1/1),不会出现两个相同的分数。若分子或者分母大于n,则去掉该分数,将剩下的分数,从小到大排序,得到数列F。

根据这个思路,代码也比较好写

#include <bits/stdc++.h>
using namespace std;

int n;

void dfs(int a1, int b1, int a2, int b2) //a1/b1 , a2/b2
{
    if (b1 + b2 > n)
        return;
    dfs(a1, b1, a1 + a2, b1 + b2);//先左边,左边比较小
    printf("%d/%d ",a1+a2,b1+b2);
    dfs(a1 + a2, b1 + b2, a2, b2);//右边
}

int main()
{
    scanf("%d",&n); //序列级数
    printf("0/1 ");
    dfs(0, 1, 1, 1); //会从小到大输出结果
    printf("1/1\n");
    return 0;
}

 正确性:

如何保证这种方法生成的都是最简分数?

利用性质3和数学归纳法易证

如何保证不重不漏?

不重:因为有序,所以,不重,为什么有序?根据该算法思想显然,不显然的话看代码就显然了

不漏:每个分数都是从其一个上界和下届逼近,类似二分,显然不漏

例题:

POJ2478 Farey Sequence 

POJ3090 Visible Lattice Points

HDU6624 fraction   (这一题算是法雷数列的一个扩展,就是求两个分数之间分母最小的分数为多少)

 

posted @ 2019-08-18 15:15  Zeronera  阅读(2480)  评论(0编辑  收藏  举报