在我们所知道的范围内,解数列题最有效的方法是先从可能产生所求数列的无穷级数开刀。
——葛立恒,高德纳,帕塔许尼克,《具体数学:计算机科学基础》
斐波那契数列指的是这样一个数列:1、1、2、3、5、8、13、21、……
先来一波看起来蛮难理解的定义:
下面是图片中的式子怎么得来的推导:
从简单的等比数列出发:
(1 + x + x2 + x3 + … + xn)(1 - x) = 1 - xn+1
等式两边同时除以 1 - x,为了不使分母为0,我们假设1 - x 不等于0
1 + x + x2 + x3 + … + xn = (1 - xn+1) / (1 - x)
这就是一个首项为1,公比为x的等比数列
接下来说说等比数列的无穷级数
x 的绝对值比 1 小时,也就是说 |x| < 1 时,如果 n 趋向于无穷大的话,那么 xn+1 趋向于 0,以下式子也就成立了:
1 + x + x2 + x3 + … + xn = 1 / (1 - x)
这样就求出了无穷级数。|x| < 1 这个条件是 n 趋向于无穷大时,xn+1 趋向于 0 的必要条件
向生成函数进军:
生成函数定义:x的幂的无限和,也就是幂级数
运用生成函数来求数列的通项
将斐波那契数列的通项 Fn 表示成 “关于 n 的有限项代数式”
在函数 F(x) 中,如果将 xn 这一项的系数用Fn 来表示,那么整个函数就可以用以下式子表示出来
我们知道 Fn-2 和 Fn-1 相加得到 Fn ,那么该如何让F(x)中系数为这两项的项相加呢(x的幂次方不同,不能直接相加)
x的幂次方互不相同,将不同的部分乘上x就好了。我们将 F(x) 分别和 x2 ,x1 ,x0 相乘后的式子写出来:
将式子A + 式子B - 式子C,式子左边变成以下形式:
式子右边变为以下形式:
已知 F0 = 0,F1 = 1,Fn-2 + Fn-1 - Fn = 0,所以得到:
F(x) · (x2 + x - 1) = -x
两边同时除以 (x2 + x - 1),整理后就能得到 F(x) 的有限项代数式:
F(x) = x / (1 - x - x2)
用无穷级数来表示
将 F(x) 有限项代数式拆成两个分式相加:
假设有4个未知常数R,S,r,s
计算此式子
即:
比较等式左右两边后,只要确定常数 R,S,r,s 为多少即可
将R和S分别转化成只含有r和s的关系式:
题目地址 蓝桥杯试题 历届试题 斐波那契
http://lx.lanqiao.cn/problem.page?gpid=T121
题目描述
斐波那契数列大家都非常熟悉。它的定义是:
f(x) = 1 … (x=1,2)
f(x) = f(x-1) + f(x-2) … (x>2)
对于给定的整数 n 和 m,我们希望求出:
f(1) + f(2) + … + f(n)
的值。但这个值可能非常大,所以我们把它对 f(m) 取模。
公式如下
但这个数字依然很大,所以需要再对 p 求模。
输入格式
输入为一行用空格分开的整数 n m p (0 < n, m, p < 10^18)
输出格式
输出为1个整数,表示答案
样例输入
2 3 5
样例输出
0
样例输入
15 11 29
样例输出
25
思路
斐波那契数列:1、1、2、3、5、8、13、21、……、an
求和:Sn = a1 + a2 + a3 + … + an
Sn = 1 + a1 + a2 + a3 + … +an - 1
因为a2等于1,所以Sn = a2 + a1 + a2 + a3 + … + an - 1
即:Sn = a2 + a1 + a2 + a3 + … + an - 1
Sn = a3 + a2 + a3 + … + an - 1
Sn = a3 + a2 + a3 + … + an - 1
Sn = a4 + a3 + … + an - 1
……
Sn = an + an-1 + an - 1
即:Sn = 2an + an-1 - 1 = an+2 - 1
证毕
还有另一种证明方式 [数列的递推公式求通项]:
https://blog.csdn.net/ftx456789/article/details/82348742
本题具体公式: (an+2 - 1) % am % p
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
ll MOD;
ll quick_multi_mod(ll a, ll b)
{
ll ans = 0;
while (b){
if (b & 1) ans = (ans + a) % MOD;
a = (a + a) % MOD;
b >>= 1;
}
return ans;
}
void Matrix(vector< vector<ll> > &a, vector< vector<ll> > b){
vector< vector<ll> > temp(2, vector<ll>(2, 0));
for (int i = 0; i < 2; i++){
for (int j = 0; j < 2; j++){
for (int k = 0; k < 2; k++){
temp[i][j] = (temp[i][j] % MOD + quick_multi_mod(a[i][k], b[k][j])) % MOD;
}
}
}
for (int i = 0; i < 2; i++){
for (int j = 0; j < 2; j++){
a[i][j] = temp[i][j]; // 赋值
}
}
}
ll quick_pow_Matrix_mod(ll n)
{
vector< vector<ll> > ans(2, vector<ll>(2, 0));
vector< vector<ll> > temp(2, vector<ll>(2, 0));
temp[0][1] = 1, temp[1][0] = 1, temp[1][1] = 1;
ans[0][0] = 1, ans[1][1] = 1;
while (n){
if (n & 1) Matrix(ans, temp);
Matrix(temp, temp);
n >>= 1;
}
return ans[0][1];
}
ll quick_multi(ll a, ll b)
{
ll ans = 0;
while (b){
if (b & 1) ans = ans + a;
a = a + a;
b >>= 1;
}
return ans;
}
void Matrix2(vector< vector<ll> > &a, vector< vector<ll> > b){
vector< vector<ll> > temp(2, vector<ll>(2, 0));
for (int i = 0; i < 2; i++){
for (int j = 0; j < 2; j++){
for (int k = 0; k < 2; k++){
temp[i][j] = temp[i][j]+ quick_multi(a[i][k], b[k][j]);
}
}
}
for (int i = 0; i < 2; i++){
for (int j = 0; j < 2; j++){
a[i][j] = temp[i][j]; // 赋值
}
}
}
ll quick_pow_Matrix(ll n)
{
vector< vector<ll> > ans(2, vector<ll>(2, 0));
vector< vector<ll> > temp(2, vector<ll>(2, 0));
temp[0][1] = 1, temp[1][0] = 1, temp[1][1] = 1;
ans[0][0] = 1, ans[1][1] = 1;
while (n){
if (n & 1) Matrix2(ans, temp);
Matrix2(temp, temp);
n >>= 1;
}
return ans[0][1];
}
int main(){
ll n, m, fib_m;
scanf("%lld%lld%lld", &n, &m, &MOD);
if (m > n + 2) // 如果m大于n+2,不需要计算f(m)的值
printf("%lld\n", (quick_pow_Matrix_mod(n + 2) - 1) % MOD);
else{ // 否则需要模上f(m)
fib_m = quick_pow_Matrix(m); // 计算fib_m的值
// 第m项可以不优化求出来,所以第n+2项也可以不取模优化
printf("%lld\n", (quick_pow_Matrix(n + 2) % fib_m - 1) % fib_m % MOD);
}
return 0;
}
————————————————
参考大佬博客
https://blog.csdn.net/junfriends/article/details/6647086