斐波那契数列

目录

一,斐波那契数列(Fibonacci sequence)

二,斐波那契—卢卡斯数列

1,斐波那契—卢卡斯数列

2,斐波那契—卢卡斯数列群

3,斐波那契—卢卡斯数列的通项公式

三,斐波那契数列模n的周期

1,基础知识

2,模p的周期

(1)代数整数表示法

(2)定理1

(3)定理2

(4)模p的周期T

3,模p^k的周期

4,模n的周期

四,卢卡斯数列模n的周期

1,模p的周期

2,模p^k的周期

3,模n的周期

五,斐波那契数列的性质

1,常用恒等式

2,常用求和式

3,斐波那契互模

4,gcd

5,齐肯多夫定理

6,其他性质

六,OJ实战

1,求斐波那契数列的水题

CSU 内部题 Neptune'Pudding(2017年院赛A题)

CSU 1402 Fibonacci Multiply

CSU 1587 爬楼梯

HDU 2041 超级楼梯

HDU 2046 骨牌铺方格

HDU 2044 一只小蜜蜂...

HDU 1021 Fibonacci Again

力扣 509. 斐波那契数

2,求斐波那契数列

OpenJ_Bailian 2758 菲波那契数列(快速幂模板一)

3,模的周期

HDU 3977 Evil teacher(斐波那契数列模n的周期)

HDU 1005 Number Sequence(周期是48?不,是336!)

4,互模

51Nod 1365 Fib(N) mod Fib(K)  (快速幂模板二)

5,拆分

力扣 1414. 和为 K 的最少斐波那契数字数目


一,斐波那契数列(Fibonacci sequence)

数列:0、1、1、2、3、5、8、13、21、34、……

递推式:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(≥ 2,∈ N*)

通项公式:F\left ( n \right )=\frac{1}{\sqrt{5}}\left ( \frac{1+\sqrt{5}}{2} \right )^n-\frac{1}{\sqrt{5}}\left ( \frac{1-\sqrt{5}}{2} \right )^n

2个特征值是用特征方程求出来的,而系数根据前2项可以确定,显然n=0时值为0,n=1时值为1

二,斐波那契—卢卡斯数列

1,斐波那契—卢卡斯数列

凡是符合F(n) = F(n-1)+ F(n-2) ,对所有n>2都成立的数列,都叫斐波那契—卢卡斯数列,也叫广义斐波那契数列

根据F(1)和F(2)的值,就可以确定整个数列,所以我们用F[a,b]表示所有的斐波那契—卢卡斯数列。

其中几个特殊的:

F[1,1] 是斐波那契数列

F[1,2] 是斐波那契数列去掉第一项得到的数列

F[1,3] 是卢卡斯数列

F[0,0] 是恒为0的数列

2,斐波那契—卢卡斯数列群

任意两个或两个以上斐波那契—卢卡斯数列之和或差仍然是斐波那契—卢卡斯数列。

所以,所有的斐波那契—卢卡斯数列构成一个群。

3,斐波那契—卢卡斯数列的通项公式

F[a,b]的通项公式是F\left ( n \right )=A\left ( \frac{1+\sqrt{5}}{2} \right )^n+B\left ( \frac{1-\sqrt{5}}{2} \right )^n

其中,A=\frac{\left ( 3-\sqrt{5} \right )a-\left ( 1-\sqrt{5} \right )b}{2\sqrt{5}},\, B=\frac{\left ( 1+\sqrt{5} \right )b-\left ( 3+\sqrt{5} \right )a}{2\sqrt{5}}

三,斐波那契数列模n的周期

1,基础知识

勒让德符号、欧拉准则、二次互反律 数论_nameofcsdn的博客-CSDN博客

数论组合 数论_nameofcsdn的博客-CSDN博客

2,模p的周期

(1)代数整数表示法

(2)定理1

F_p \equiv \left ( \frac{p}{5} \right )(mod\, p)

(3)定理2

F_{p- \left ( \frac{p}{5} \right )} \equiv 0(mod\, p)

(4)模p的周期T

(4.1)若p为奇素数,且p≡±1(mod 5)则T | p-1

(4.2)若p为奇素数,且p≡±2(mod 5)则T | 2(p+1)

(4.3)T(5)=20,T(2)=3

3,模p^k的周期

T(p^k)\mid T(p^{k-1})*p

证明简单,略。

于是,T(p^k)\mid T(p)*p^{k-1}

若p为奇素数,且p≡±1(mod 5)则T(p^k)\mid (\frac{p-1}{2})*p^{k-1}*2

若p为奇素数,且p≡±2(mod 5)则T(p^k)\mid (\frac{p+1}{2})*p^{k-1}*4

若p=5,则T(p^k)\mid p^{k}*4

若p=2,则T(p^k)\mid p^{k-1}*3

4,模n的周期

T(m)<= 6m

证明:将m因式分解:

m=\coprod _i p_i^{k_i}

T(m)=lcm\{T(p_i^{k_i}):i\}\leq lcm\{ T(p_i)*p_i^{k_i-1} :i\}

所以,如果m是奇数,则T(m)<= 4m,如果m是偶数,则T(m)<= 6m

当且仅当m=2*5^k时,T(m)= 6m

四,卢卡斯数列模n的周期

1,模p的周期

F(n)= A / 2^(n-1),A的含义同上。

F(p)≡1(mod p),证明同理,略。

若p为奇素数,且p≡±1(mod 5),则F(p-1)≡2(mod p),则T | p-1

若p为奇素数,且p≡±2(mod 5),则F(p+1)≡-2(mod p),则T | 2(p+1)

T(5)=4,T(2)=3

也就是说,除了p=5的情况之外,其他结论都和斐波那契数列相同。

2,模p^k的周期

若p为奇素数,且p≡±1(mod 5)则T(p^k)\mid (\frac{p-1}{2})*p^{k-1}*2

若p为奇素数,且p≡±2(mod 5)则T(p^k)\mid (\frac{p+1}{2})*p^{k-1}*4

若p=5,则T(p^k)\mid p^{k-1}*4

若p=2,则T(p^k)\mid p^{k-1}*3

同样的,除了p=5的情况之外,其他结论都和斐波那契数列相同。

3,模n的周期

T(m)<= 4m

当且仅当m=6时,T(m)= 4m

五,斐波那契数列的性质

1,常用恒等式

(1)F_n^2-F_{n-1}F_{n+1}=(-1)^{n-1}

(2)F_m=F_nF_{m-n+1}+F_{n-1}F_{m-n},特别的,F_{2n}=F_n(F_{n-1}+F_{n+1})

2,常用求和式

(1)前n项和

F_1+F_2+...+F_n=F_{n+2}-1

F_1^2+F_2^2+...+F_n^2=F_nF_{n+1}

(2)隔项求和

F_1+F_3+F_5+...+F_{2n-1}=F_{2n}

F_2+F_4+F_6+...+F_{2n}=F_{2n+1}-1

(3)隔2项求和

F_1+F_4+F_7+...+F_{3n-2}=\frac{F_{3n}}{2}

F_2+F_5+F_8+...+F_{3n-1}=\frac{F_{3n+1}-1}{2}

F_3+F_6+F_9+...+F_{3n}=\frac{F_{3n+2}-1}{2}

3,斐波那契互模

(1)由F_m=F_nF_{m-n+1}+F_{n-1}F_{m-n}可得F_m\equiv F_{n-1}F_{m-n}(modF_n)

对任意t,F_m\equiv F_{n-1}^tF_{m-tn}(modF_n)

(2)由F_n^2-F_{n-1}F_{n+1}=(-1)^{n-1}可得F_{n-1}^2\equiv (-1)^n(modF_n)

设2nt<=m<2n(t+1),则F_m\equiv F_{n-1}^{2t}F_{m-2tn}\equiv(-1)^{tn}F_{m-2tn}(modF_n)

(3)根据F_{2n-a}\equiv (-1)^{n+a+1}F_a(modF_n),结论可以进一步细化为:

若2nt<=m<=2nt+n,则F_m\equiv(-1)^{tn} F_{m\%n} (modF_n)

若2nt+n<=m<2nt+2n,则F_m\equiv(-1)^{tn+m+n+1}F_{n-m\%n}(modF_n)

如果n是偶数,则(-1)^{tn+m+n+1}=(-1)^{m+1},如果n是奇数,则(-1)^{tn+m+n+1}=(-1)^{m+t}

4,gcd

(1)gcd(F_n,F_{n-1})=1

(2)根据F_m\equiv F_{n-1}^tF_{m-tn}(modF_n)可得 gcd(F_m,F_n)=gcd(F_{m-tn},F_n)  

进一步可得gcd(F_m,F_n)=F_{gcd(m,n)}

5,齐肯多夫定理

斐波那契数列:1,2,3,5,8,13......

任何正整数都可以唯一地表示成若干个不连续的斐波那契数之和。

首先,存在性。在上面的百科链接里面,有数学归纳法的证明。

然后,唯一性。可以用反证法加上无穷递降法证明出来。

假设n是最小的有2种表示法的整数,其中一种表示中,最大的数是a,另外一种表述中,最大的数是b。

这里需要一个简单的结论:

引理:如果m是斐波那契数,那么不超过m的所有斐波那契数中,选出若干个不连续的,能够得到的最大的和刚好就是m-1

比如说,在1,2,3,5,8,里面,最大的和就是1+3+8=12,刚好是13-1。

无论m是第奇数个斐波那契数,还是第偶数个,都是一样的,证明很简单,略。

所以,根据这个引理,a和b只能相等。

因为这是2种不同的表示法,所以n一定要比a大。

那么n-a就有2种不同的表示法,即将上面的2个不同的表示法里面删掉相同的数a、b,得到的自然是不同的表示法。

这个,n-a小于n,与n的最小性矛盾!

所以,表示法是唯一的。

在斐波那契博弈里面,用的就是这个定理。

6,其他性质

六,OJ实战

1,求斐波那契数列的水题

CSU 内部题 Neptune'Pudding(2017年院赛A题)

题目:

Description:
Neptune likes pudding very much! And she always indulges in eatting pudding and napping rather than does CPU's work. The pudding have two types which one is made by her good friend Compa and the other can be bought in shop. Neptune will eat pudding one by one. Because she perfers Compa's pudding rathet than shop's, she doesn't want to eat two shop's pudding in continually two times. Assuming she will eat n puddings, could you help the kawaii girl to let her know how many ways of eatting pudding in her habit?
Neptune十分喜欢布丁!同时她总是沉浸在吃布丁和小睡的世界中而忘记了女神的工作。布丁一共有两个品种,其中一个是她的一个好朋友Compa做的,另外一个就是可以再商店买到的普通布丁。Neptune会一个一个地把布丁吃掉。由于她相比商店的布丁更加喜欢Compa的布丁,因此她不愿意连续吃两个商店的布丁。现在假设Neptune一共要吃n个布丁,你能帮助这个可爱的女孩子计算一共有多少种满足她吃布丁的习惯的方法数吗?
Input:
First line is a integer t standing for test times. Next t line, there will just one integer n in a line which stands for pudding number (n<= 90) of eaten by Neptune.
第一行是一个整数t,代表有t组测试。接下来t行,每一行一个整数n,代表Neptune要吃n个布丁
Output
For each given pudding number, you should output how many ways of satisfying the condition.
对于每一个数n,输出满足条件的方法数
Sample Input:
2
1
2
Sample Output:
2
3

#include<iostream>
using namespace std;
 
int main()
{
	long long list[95];
	list[0]=1,list[1]=2;
	for(int i=2;i<=90;i++)list[i]=list[i-1]+list[i-2];
	int n;
	cin>>n;
	while(cin>>n)cout<<list[n]<<endl;
	return 0;
}

CSU 1402 Fibonacci Multiply

题目:

Description
In mathematics, the Fibonacci number are the number in the following integer sequence:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34….
The nth Fibonacci number Fn, is defined by the recurrence relation
Fn = Fn - 1 + Fn - 2
with F0 = 0, F1 = 1.
Given two positive integers x, y, calculate (Fx * Fy) % 1000000007.
Input
The first line contains the number of test cases T (1 <= T <= 50).
For each test case, there is only one line with two integers x, y (1 <= x, y <= 106).
Output
For each test case, output (Fx * Fy) % 1000000007.

Sample Input
3
3 4
7 1
8 8
Sample Output
6
13
441
代码:

#include<iostream>
using namespace std;
 
int f[1000001];
 
int main()
{
	f[0] = 0, f[1] = 1;
	for (int i = 2; i <= 1000000; i++)f[i] = (f[i - 1] + f[i - 2]) % 1000000007;
	int t, x, y;
	cin >> t;
	while (t--)
	{
		cin >> x >> y;
		long long r = f[x];
		cout << r*f[y] % 1000000007 << endl;
	}
	return 0;
}

CSU 1587 爬楼梯

题目:

Description

小时候我们都玩过爬楼梯的游戏:两人猜拳,赢了可向上爬一级,谁先到最高级则获胜。作为大学生,我们应该玩一个更有水平的游戏。
现在一个人要上n级楼梯,每一步可以选择上一级或者上两级,但是不能后退。求上这n级楼梯的方案数。

Input

第一行只有一个整数T(1<=T<=45),表示数据组数。
下面的T行每一行有一个整数n(1<=n<=45),表示有多少级楼梯。

Output

对于每一组数据输出一个整数s,表示方案数。

Sample Input

4
1
2
3
4
Sample Output

1
2
3
5

这个题目其实就是求斐波那契数列。

因为输入的数据每个数都不会超过45,所以应该事先用数组存储计算结果。

代码:
 

#include<iostream>
using namespace std;
 
int main()
{	
	int list[46];
	list[0] = 1;
	list[1] = 1;
	for (int i = 2; i <= 45; i++)list[i] = list[i - 1] + list[i - 2];
	int t, n;
	cin >> t;
	while (t--)
	{
		cin >> n;
		cout << list[n]<<endl;
	}
	return 0;
}

HDU 2041 超级楼梯

题目:


Description

有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法?
Input

输入数据首先包含一个整数N,表示测试实例的个数,然后是N行数据,每行包含一个整数M(1<=M<=40),表示楼梯的级数。
Output

对于每个测试实例,请输出不同走法的数量
Sample Input

2
2
3
Sample Output

1
2

斐波那契
代码:

#include<iostream>
#include<stdio.h>
using namespace std;

long long list[50];

int main()
{
	list[1] = 1;
	list[2] = 2;
	for (int i = 3; i < 50; i++)list[i] = list[i - 1] + list[i - 2];
	int n, a;
	cin >> n;
	while (n--)
	{
		cin >> a;
		cout << list[a-1] << endl;
	}
	return 0;
}

HDU 2046 骨牌铺方格

题目:
Description

在2×n的一个长方形方格中,用一个1× 2的骨牌铺满方格,输入n ,输出铺放方案的总数. 
例如n=3时,为2× 3方格,骨牌的铺放方案有三种,如下图: 

Input

输入数据由多行组成,每行包含一个整数n,表示该测试实例的长方形方格的规格是2×n (0<n<=50)。 
Output

对于每个测试实例,请输出铺放方案的总数,每个实例的输出占一行。 
Sample Input

1
3
2
Sample Output

1
3
2

这是一个递归问题,答案是斐波那契数列。

代码:
 

#include<iostream>
#include<stdio.h>
using namespace std;

long long list[51];

int main()
{
	list[1] = 1;
	list[2] = 2;
	for (int i = 3; i <= 50; i++)list[i] = list[i - 1] + list[i - 2];
	int a;
	while (cin >> a)cout << list[a] << endl;
	return 0;
}

HDU 2044 一只小蜜蜂...

题目:
Description

有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。 
其中,蜂房的结构如下所示。 
 
Input

输入数据的第一行是一个整数N,表示测试实例的个数,然后是N 行数据,每行包含两个整数a和b(0<a<b<50)。 
Output

对于每个测试实例,请输出蜜蜂从蜂房a爬到蜂房b的可能路线数,每个实例的输出占一行。 
Sample Input

2
1 2
3 6
Sample Output

1
3
代码:

#include<iostream>
#include<stdio.h>
using namespace std;

long long list[50];

int main()
{
	list[1] = 1;
	list[2] = 2;
	for (int i = 3; i < 50; i++)list[i] = list[i - 1] + list[i - 2];
	int n, a, b;
	cin >> n;
	while (n--)
	{
		cin >> a >> b;
		cout << list[b - a] << endl;
	}
	return 0;
}

HDU 1021 Fibonacci Again

题目:


Description

There are another kind of Fibonacci numbers: F(0) = 7, F(1) = 11, F(n) = F(n-1) + F(n-2) (n>=2). 
Input

Input consists of a sequence of lines, each containing an integer n. (n < 1,000,000). 
Output

Print the word "yes" if 3 divide evenly into F(n). 

Print the word "no" if not. 
Sample Input

0
1
2
3
4
5
Sample Output

no
no
yes
no
no
no

把mod3的数列列出来找规律即可。

不管初始值是多少,一定有一个不超过8的周期,所以不需要列出很多项即可完美解决。

代码:
 

#include<iostream>
using namespace std;

int main()
{	
	int n;
	while (cin >> n)cout << ((n % 4 == 2) ? "yes\n" : "no\n");
	return 0;
}

力扣 509. 斐波那契数

 斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给你 n ,请计算 F(n) 。

示例 1:

输入:2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1
示例 2:

输入:3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2
示例 3:

输入:4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3
 

提示:

0 <= n <= 30

class Solution {
public:
    int fib(int n) {        
        static int ans[101]={0,1};
        if(n<2)return ans[n];
        if(ans[n])return ans[n];
        return ans[n]=(fib(n-1)+fib(n-2))%1000000007;
    }
};

2,求斐波那契数列

OpenJ_Bailian 2758 菲波那契数列(快速幂模板一)

题目:

菲波那契数列是指这样的数列: 数列的第一个和第二个数都为1,接下来每个数都等于前面2个数之和。 
给出一个正整数a,要求菲波那契数列中第a个数对1000取模的结果是多少。Input第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数a(1 <= a <= 1000000)。Outputn行,每行输出对应一个输入。输出应是一个正整数,为菲波那契数列中第a个数对1000取模得到的结果。Sample Input

4
5
2
19
1

Sample Output

5
1
181
1

代码:

#include <iostream>
#include <vector>
using namespace std;

int mod = 1000;

template <typename A> vector<vector<A>> opMatrixMulti(vector<vector<A>> x, vector<vector<A>> y)
{
    vector<vector<A>> ans = x;
    for (int i = 0; i < ans.size(); i++) {
        for (int j = 0; j < ans.size(); j++) {
            ans[i][j] = 0;
            for (int k = 0; k < ans.size(); k++)
                ans[i][j] += x[i][k] * y[k][j] % mod, ans[i][j] %= mod;
        }
    }
    return ans;
}

template <typename A, typename N> A aijiMulti(A a, N n, A (*pfunc)(A, A))
{
    if (n <= 1) return a;
    A ans = aijiMulti(a, n / 2, pfunc);
    ans = pfunc(ans, ans);
    if (n % 2) ans = pfunc(ans, a);
    return ans;
}

long long fib(long long n)
{
    vector<vector<long long>> in(2);
    for (int i = 0; i < 2; i++) in[i].resize(2);
    in[0][0] = 1, in[0][1] = 1;
    in[1][0] = 1, in[1][1] = 0;
    vector<vector<long long>> ans = aijiMulti(in, n, opMatrixMulti);
    return ans[0][1];
}

int main()
{
    int n;
    cin >> n;
    while (cin >> n)cout << fib(n) << endl;
    return 0;
}

用vector传递的速度比较慢,下面的快速幂模板二的计算速度快一点。

3,模的周期

HDU 3977 Evil teacher(斐波那契数列模n的周期)

题目:

In the math class, the evil teacher gave you one unprecedented problem! 

Here f(n) is the n-th fibonacci number (n >= 0)! Where f(0) = f(1) = 1 and for any n > 1, f(n) = f(n - 1) + f(n - 2). For example, f(2) = 2, f(3) = 3, f(4) = 5 ... 

The teacher used to let you calculate f(n) mod p where n <= 10^18 and p <= 10^9, however , as an ACMER, you may just kill it in seconds! The evil teacher is mad about this. Now he let you find the smallest integer m (m > 0) such that for ANY non-negative integer n ,f(n) = f(n + m) (mod p) . For example, if p = 2, then we could find know m = 3 , f(0) = f(3) = 1(mod 2), f(1) = f(4) (mod 2) .... 

Now the evil teacher will only give you one integer p( p <= 2* 10^9), will you tell him the smallest m you can find ?
InputThe first line is one integer T indicates the number of the test cases. (T <=20) 

Then for every case, only one integer P . (1 <= P <= 2 * 10^9, the max prime factor for P is no larger than 10^6)OutputOutput one line. 

First output “Case #idx: ”, here idx is the case number count from 1.Then output the smallest m you can find. You can assume that the m is always smaller than 2^64 .Sample Input

11 
19 
61 
17 
67890
Sample Output
Case #1: 10 
Case #2: 18 
Case #3: 60 
Case #4: 36 
Case #5: 4440

代码:
 

#include<iostream>
using namespace std;
#define ll long long
 
int fb[2000000];
int list[1000001], p[78498];//78497个素数
void getp()//在p数组中存所有不超过1000000的素数
{
	p[0] = 2;
	int key = 0;
	for (int i = 0; i <= 1000000; i++)list[i] = i % 2;
	for (int i = 3; i <= 1000000; i += 2)if (list[i])
	{
		p[++key] = i;
		for (int j = i + i; j <= 1000000; j += i)list[j] = 0;
	}
}
 
ll gcd(ll a, ll b)
{
	if (b)return gcd(b, a%b);
	return a;
}
 
ll lcm(ll a, ll b)
{
	return a / gcd(a, b)*b;
}
 
ll fp(int n)//n是素数
{
	fb[0] = 0, fb[1] = 1;
	for (int i = 2;; i++)
	{
		fb[i] = (fb[i - 1] + fb[i - 2]) % n;
		if (fb[i - 1] == 1 && fb[i] == 0)return i;
	}
	return 0;
}
 
ll f2(ll n)
{
	ll ans = 1, m;
	int a;
	for (int i = 0; i < 78497; i++)
	{
		a = p[i];
		if (n%a)continue;
		m = 1;
		while (n%a == 0)m *= a, n /= a;
		ans = lcm(ans, m / a * fp(a));
	}
	return ans;
}
 
int main()
{
	getp();
	int T;
	cin >> T;
	ll n;
	for (int i = 1; i <= T; i++)
	{
		cin >> n;
		cout << "Case #" << i << ": " << f2(n) << endl;
	}
	return 0;
}

解题思路:

把n因式分解成各个素数的幂,

为了完成因式分解要预先把所有可能的素数都计算出来存到一个数组里面,这部分代码和POJ - 2689 Prime Distance(2次用筛法)这里面是一样的

求出斐波那契数列模各个素数幂的周期,所有周期的最小公倍数就是答案。

要想求出斐波那契数列模素数幂的周期,只需要求出模这个素数的周期。

根据素数的大小和上面的理论进行计算发现,斐波那契数列模素数的周期不会超过2*10^6,所以可以直接暴力求取。

HDU 1005 Number Sequence(周期是48?不,是336!)

题目:


Description

A number sequence is defined as follows: 

f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7. 

Given A, B, and n, you are to calculate the value of f(n). 
Input

The input consists of multiple test cases. Each test case contains 3 integers A, B and n on a single line (1 <= A, B <= 1000, 1 <= n <= 100,000,000). Three zeros signal the end of input and this test case is not to be processed. 
Output

For each test case, print the value of f(n) on a single line. 
Sample Input

1 1 3
1 2 10
0 0 0
Sample Output

2
5

显然,这是一个找周期的问题。

我们很容易推出,一定有周期,而且最小周期不超过49.

(下面的论述中,都假设a和b小于7,即已经mod7)

而且,如果a、b不全为0,那么一定是从(1,1)(即第1项)开始循环的

当a=b=0时,不是从第1项开始,而是从第3项开始循环。


我最开始的方法是,对于每组给的a、b,求出最小正周期

代码:
 

#include<iostream>
using namespace std;

int getT(int a, int b)
{
	if (a == 0 || b == 0)return 12;
	if ((a + b) % 7 == 1)return 1;
	int T = 0, x1 = 1, x2 = 1;
	while (true)
	{
		int temp = (b*x1 + a*x2) % 7;
		x1 = x2;
		x2 = temp;
		T++;
		if (x1 == 1 && x2 == 1)break;
	}
	return T;
}

int main()
{
	int a, b, n;
	while (cin >> a >> b >> n)
	{
		if (n == 0)break;
		if (a % 7 == 0 && b % 7 == 0)
		{
			cout << (n<3) << endl;
			continue;
		}
		int x1 = 1, x2 = 1;
		if (n>20)n = (n - 20) % getT(a % 7, b % 7) + 20;		
		if (n > 2)n -= 2;
		else n = 0;
		while (n--)
		{
			int temp = (b*x1 + a*x2) % 7;
			x1 = x2;
			x2 = temp;
		}
		cout << x2 << endl;
	}
	return 0;
}

这个是AC了的,没有任何问题。

其中,当b=0的时候,6一定是周期,这是费马小定理。

当a=0的时候,恰好奇数列和偶数列是一样的,而且6一定是它们的周期,所以12是数列的周期。

例如,当a=0,b=3时,前14项为1,1,3,3,2,2,6,6,4,4,5,5,1,1,周期为12

然后我发现vj里面有个AC的代码很短,就看了一下,发现他是直接以48为周期。

网上搜了一下,很多人说48一定是周期,甚至还有人说49是周期。。。

但是我枚举了a和b(一共也就49种情况)

代码:
 

int main()
{	
	for (int i = 0; i < 7; i++)
	{
		for (int j = 0; j < 7; j++)cout << getT(i, j) << " ";
		cout << endl;
	}	
	return 0;
}

结果是:

很明显,有14、21、42的存在,48不是周期!

所以说,应该是VJ给的测试数据很水,所以有很多代码都浑水摸鱼了。

当然,336一定是周期,有了这个信息,也可以写出很简洁的代码了。

代码:

#include<iostream>
using namespace std;
int main()
{	
	int a, b, n;
	while (cin >> a >> b >> n)
	{
		if (n == 0)break;
		if (a % 7 == 0 && b % 7 == 0)
		{
			cout << (n<3) << endl;
			continue;
		}
		int x1 = 1, x2 = 1;
		n = (n + 333) % 336 + 1;
		while (n--)
		{
			int temp = (b*x1 + a*x2) % 7;
			x1 = x2;
			x2 = temp;
		}
		cout << x2 << endl;
	}
	return 0;
}

这个也很快,也是0ms AC

4,互模

51Nod 1365 Fib(N) mod Fib(K)  (快速幂模板二)

Fib(N)表示斐波那契数列的第N项(F(0) = 0, F(1) = 1),给出N和K,求Fib(N) mod Fib(K)。由于结果太大,输出Mod 1000000007的结果。

Input

第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 50000) 第2 - T + 1行:每行2个数N, K(1 <= N, K <= 10^18)

Output

共T行:对应Fib(N) mod Fib(K)的结果再Mod 1000000007。

Sample Input

2
5 5
13 5

Sample Output

0
3
#include<iostream>
#include<vector>
using namespace std;

int mod = 1000000007;

long long  a, b, c, d;
long long  x1, x2, x3, x4;

void f(long long n)
{
    if (n == 0)
    {
        a = 1,b = 0,c = 0,d = 1;
        return;
    }
    f(n / 2);
    x1 = a*a + b*c,x2 = (a + d)*b,x3 = (a + d)*c,x4 = b*c + d*d;
    a = x1 % mod,b = x2 % mod,c = x3 % mod,d = x4 % mod;
    if (n % 2)c += a,a = c - a,d += b,b = d - b;
}


int main()
{
    ios::sync_with_stdio(false);
    long long t,n,k,p=1000000007,ans;
    int T;
    cin>>T;
    vector<vector<long long>> in(2);
    for (int i = 0; i < 2; i++) in[i].resize(2);
    in[0][0] = 1, in[0][1] = 1;
    in[1][0] = 1, in[1][1] = 0;
    while(T--){
        cin>>n>>k;
        t=n/k;
        if(n%k==0)ans=0;
        else if(t%2==0){
            f(n%k);
            ans=b;
            f(k);
            if(t/2%2==1&&k%2==1)ans=b-ans;
        }else{
            f(k-n%k);
            ans=b;
            f(k);
            if((n+(k%2?t/2:1))%2)ans=b-ans;
        }
        cout<<(ans%p+p)%p<<endl;
    }
    return 0;
}

5,拆分

力扣 1414. 和为 K 的最少斐波那契数字数目

给你数字 k ,请你返回和为 k 的斐波那契数字的最少数目,其中,每个斐波那契数字都可以被使用多次。

斐波那契数字定义为:

F1 = 1
F2 = 1
Fn = Fn-1 + Fn-2 , 其中 n > 2 。
数据保证对于给定的 k ,一定能找到可行解。

示例 1:

输入:k = 7
输出:2 
解释:斐波那契数字为:1,1,2,3,5,8,13,……
对于 k = 7 ,我们可以得到 2 + 5 = 7 。
示例 2:

输入:k = 10
输出:2 
解释:对于 k = 10 ,我们可以得到 2 + 8 = 10 。
示例 3:

输入:k = 19
输出:3 
解释:对于 k = 19 ,我们可以得到 1 + 5 + 13 = 19 。
 

提示:

1 <= k <= 10^9

int findMinFibonacciNumbers(int k){
    int f[45];
    f[0] = 0, f[1] = 1;
	for (int i = 2; i <= 44; i++)f[i] = f[i - 1] + f[i - 2];
    int ans=0;
    for(int i=44;i>0;i--)if(k>=f[i])
    {
        k-=f[i],ans++;
    }
    return ans;
}

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值