法雷级数[Farey Sequence]

在昨天的比赛中,A题中,有一道题,与法雷级数很是相似。但是,强大的队友们还是给推出来,是欧拉函数。ORZ。


法雷级数:

   所有分母小于等于n,并且值介于0到1之间的既约分数(分子分母互素)从小到大排列所组成的序列 。

   即 Fn = { a / b, gcd(a,b) = 1 && 0<=a<=b<=n};

如下:

  F1 = { 0 / 1, 1 / 1 };
  F2 = { 0 / 1, 1 / 2, 1 / 1 };
  F3 = { 0 / 1, 1 / 3, 1 / 2, 2 / 3, 1 / 1 };

那么一般情况下,我们都想要知道,Fn有多少个?

我们知道Fn中,相对于Fn-1,增加的就是以n为分母的元素。那么,增加的个数就是从1-n互素的个数。也就是欧拉函数。

这里我们设F(n)就是Fn的个数,E(n)为欧拉函数的值。那么结论就是:

F(n)=F(n-1)+E(n);

性质:

      第一,如果a / b, a’ / b’是Fn中相邻的两项,则有abs(a * b’ – b * a’) = 1。

      第二,如果a / b, a’’ / b’’, a’ / b’是Fn中的相邻三项,则有( a + a’ ) / ( b + b’ ) = a’’ / b’’。
                 特别地,如果a’’ / b’’是新添加的,即a’’ / b’’不属于F(n-1),则有a + a’ = a’’ && b + b’ = b’。

法雷级数推荐题目:poj2478 Farey Sequence
                                poj3090 Visible Lattice Points

那么,昨天,我们的比赛题目:点击打开链接

题目的意思就是,给一个序列,

f1=1 1.

f2=1 2 1.

f3=1 3 2 3 1.

f4=1 4 3 2 3 4 1.

fn如果相邻的两个数相加为n的话,加入序列。

求解第n个序列的增加了多少个。

可以看到,该序列与法雷级数的分母是一致的。也就是说,每次增加的就是E(n),欧拉函数的值。

代码:

 
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define LL long long
using namespace std;

//if(n%a==0&&(n/a)%a==0) then e(n)=e(n/a)*a;
//if(n%a==0&&(n/a)%a!=0) then e(n)=e(n/a)*(a-1);
LL eular(LL n){
    LL cnt=1,i;
    for(i=2;i*i<=n;i++)
    if(n%i==0){
        n=n/i;
        cnt=cnt*(i-1);
        while(n%i==0){
           n=n/i;
           cnt=cnt*i;
        }
    }
    if(n>1)
    cnt=cnt*(n-1);
    return cnt;
}

int main(){
    LL n,T;
    scanf("%lld",&T);
    while(T--&&scanf("%lld",&n)){
        printf("%lld\n",eular(n));
    }
    return 0;
}
        

比赛之前,我们都没有看到过这个法雷级数,但是,竟然,给推出来了。ORZ,队友太给力了。

还有就是,如果对于欧拉函数足够了解的话,那么,推出前几项就可以看出规律了。数论大神,ORZ。

以下是将分母小于等于n的不可约真分数按升序排序,并在第一个分数前加0/1,最后一个分数后加1/1 的 C++ 代码实现: ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; // 求两个数的最大公约数 int gcd(int a, int b) { if (b == 0) return a; return gcd(b, a % b); } // 判断一个分数是否为不可约真分数 bool isProperFraction(int numerator, int denominator) { int commonDivisor = gcd(numerator, denominator); return commonDivisor == 1 && numerator < denominator; } // 比较两个分数的大小(按升序排序) bool compareFractions(pair<int, int> a, pair<int, int> b) { return a.first * b.second < b.first * a.second; } // 生成n级的法雷序列 vector<pair<int, int>> generateFareySequence(int n) { vector<pair<int, int>> fareySequence; fareySequence.push_back(make_pair(0, 1)); for (int denominator = n; denominator >= 1; denominator--) { for (int numerator = 1; numerator < denominator; numerator++) { if (isProperFraction(numerator, denominator)) { fareySequence.push_back(make_pair(numerator, denominator)); } } } fareySequence.push_back(make_pair(1, 1)); sort(fareySequence.begin(), fareySequence.end(), compareFractions); return fareySequence; } int main() { int n; cout << "请输入自然数n(n<=10): "; cin >> n; vector<pair<int, int>> fareySequence = generateFareySequence(n); for (auto fraction : fareySequence) { cout << fraction.first << "/" << fraction.second << endl; } return 0; } ``` 在上述代码中,我们首先定义了一个 `pair<int, int>` 类型的向量 `fareySequence` 来存储分数。然后,我们使用 `generateFareySequence` 函数生成了 n 级的法雷序列,并将其存储在 `fareySequence` 中。最后,我们按顺序输出法雷序列中的每个分数。 请注意,为了使分数能够按升序排序,我们还定义了一个 `compareFractions` 函数来比较两个分数的大小。在输出法雷序列时,我们使用 `fraction.first` 和 `fraction.second` 分别表示分数的分子和分母。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值