快速幂与矩阵乘法的结合(斐波那契数列)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,p;
ll m;
struct node{
    //save
    ll g[4][4];
}f,res;
void ORI(node &x){ //单位矩阵
    for(int i = 1;i <= 2;i++){
        for(int j = 1;j <= 2;j++){
            if(i==j) x.g[i][j] = 1LL;
            else x.g[i][j] = 0LL;
        }
    }
}
void sq_t(node &x,node &y,node &z){
    memset(z.g,0,sizeof(z.g));//预设结果矩阵为空
    int i,j,k;
    for(i = 1;i <= 2;i++){
        for(k = 1;k <= 2;k++){
            for(j = 1;j <= 2;j++){
                z.g[i][k] += x.g[i][j] * y.g[j][k]; //计算
                if(z.g[i][k] >= m) {z.g[i][k] %= m;} //驱魔
                
            }
        }
    }
}
void outp(node &x){
    for(int i = 1;i <= 2;i++){
        for(int k = 1;k <= 2;k++){
            cout<<x.g[i][k]<<' ';
        }
        printf("\n");
    }
    printf("END\n\n");
}
void ksm(int yy){
    ORI(res);//预设结果为单位矩阵(y = 1)
    node temp,t;
    temp = f;//预设操作矩阵为f矩阵
    while(yy){
        if(yy&1) {
            sq_t(res,temp,t);res = t;//y = y*x
        }
        sq_t(temp,temp,t);temp = t;//x = x*x
        yy>>=1;
    }
}
ll solve(){         //即原递推函数,需要考虑特判_公式_取模
    if(n <= 2) return 1LL;
    ksm(n - 2);  //此时的res为基本数组的幂 ,需乘(1,1),即同行下相加为对应列 数字
    ll ans = res.g[1][1] + res.g[2][1];//结合上面就好理解了,ans为乘完(1,1)后第一个数
    if(ans >= m) ans %= m;//驱魔
    return ans;
}
int main(){
    
    scanf("%d%d",&n,&p);
    m=p;
    f.g[1][1] = 1;f.g[1][2] = 1;f.g[2][1] = 1;f.g[2][2] = 0;
    //f是递推推出来的基本数组,即x^y中x
    int endr = (int)solve();
    printf("%d",endr);
    return 0;
}

上一篇:【NKOJ-2733】青蛙的约会


下一篇:最大连续区间和C++