斐波那契前 n 项和--acwing(矩阵法求斐波那契数列&&矩阵快速幂)

大家都知道 Fibonacci 数列吧,f1=1,f2=1,f3=2,f4=3,…,fn=fn−1+fn−2。
现在问题很简单,输入 n 和 m,求 fn 的前 n 项和 Snmodm。
输入格式:
共一行,包含两个整数 n 和 m。
输出格式:
输出前 n 项和 Sn mod m 的值。
数据范围:
1≤n≤2000000000,
1≤m≤1000000010

题意:求斐波那契数列前n项和
题解:这里,n的范围太大了,直接遍历肯定超时,这里用了一个矩阵快速幂的方法。
求第n项斐波那契的值,可以用矩阵的方法,如下:求第n+1项,可以通过第n项的矩阵乘以一个A矩阵就得到了第n+1项矩阵,又因为矩阵乘法具有结合律,那么就可以先计算A的(n-1)次方,然后再和fn相乘,就得到了第n+1个斐波那契数,求A的n次方可以用一个快速幂的方法
斐波那契前 n 项和--acwing(矩阵法求斐波那契数列&&矩阵快速幂)_第1张图片
同理求前n项和的话,只需要再在矩阵里面再加个元素即可,A矩阵再做个变换,即可得到公式
斐波那契前 n 项和--acwing(矩阵法求斐波那契数列&&矩阵快速幂)_第2张图片

代码:

#include 
using namespace std;

typedef long long ll;
const int N=3;

ll n,m;

void mul(int f[],int a[][N]){  //矩阵乘法快速幂,一维乘以二维
    int temp[N]={0};
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            temp[i]=(temp[i]+(ll)f[j]*a[j][i])%m;
        }
    }
    memcpy(f,temp,sizeof(temp));//sizeof必须是temp,如果是f那么大小就是个指针
}
void mul(int a[][N],int b[][N]){  //二维乘以二维
    int temp[N][N]={0};
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            for(int k=0;k<N;k++){
                temp[i][j]=(temp[i][j]+(ll)a[i][k]*b[k][j])%m;
            }
        }
    }
    memcpy(a,temp,sizeof(temp));
}
int main()
{
    cin>>n>>m;
    int f1[N]= {1,1,1};   //设置初始
    int a[N][N]={{0,1,0},{1,1,1},{0,0,1}};//快速幂的二维数组
    n--;  //求n次,那么就是f1乘以a的n减一次幂
    while(n){
        if(n&1)mul(f1,a);  //res=res*a
        mul(a,a);   //a=a*a;
        n=n>>1;
    }
    cout<<f1[2]<<endl;  //取第二位就是和
    return 0;
}

你可能感兴趣的:(数论)