快速幂:

1.求5^19,19个5相乘当然可以算出来,但是当指数特别大的时候O(n)就不行了,必须要O(logn)的算法,也就是根据位运算来求解。
19的二进制是(10011)
5^19=5^1 * 5^2 * 5^16;指数对应的二进制如下:
1---00001,2---00010,16---10000
于是我们可以设temp=5(底数),我们求出来的结果是ans;那么我们可以设置一个循环,起始条件是1,边界是n=5(指数的二进制的位数),每循环一次temp就乘一次temp(乘一次就是5^2,两次就是5^4....),同时如果此时的这一位是1,ans就乘上这个temp(根据这个步骤再结合上面的例子就可以清楚的理解代码的原理了):

#include<stdio.h>
#define ll long long
ll qpow(ll a,ll b) {
    ll ans=1;
    while(b) {
        if(b&1)    ans*=a;//当前位置是1就乘上a(底数)
        a*=a;
        b>>=1;//b的二进制向后移一位,相当于除于2,比如10011移一次就变成了1001,可以很好的达到上述模拟的效果 
    }
    return ans;
}
ll a,b;
int main() {
    while(scanf("%lld%lld",&a,&b)==2) {
        printf("%lld\n",qpow(a,b));
    }
}

矩阵:

a[i]表示斐波那契数列第i项;a[1]=1,a[2]=1;
因为a[i]=a[i-1]+a[i-2],我们就可以尝试能不能通过矩阵相乘来求斐波那契数列,就有了下面的假设;
图片说明
列出矩阵相乘的结果如下:
图片说明
两个图对比发现中间矩阵非常容易求得,于是假设成立,把初始矩阵比作a(a[i]=1,a[i-1]=1),中间矩阵比作b,求a[n]就是求a*b^(n-2)然后取第一行第一列;初始矩阵(左)和中间矩阵如下(右):
|1 1| |1 1|
|x y| |1 0|
一般的斐波那契数列用不到x,y,所以x,y可以任意取值,这里x取1,y取0方便计算;原式就变成了a[i]=b^(n-1)然后取第一行第一列.
看到这里会发现,形如a=ax+by+k的式子,给出初始的a[0],b[0]求a[n],都可以构建一个简单的矩阵用乘法来完成模拟,因为用乘法取模拟我们就可以用到快速幂来降低时间复杂度:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1e9+7; 
struct node {
    ll matrix[2][2];//结构体中的矩阵
    node() {
        memset(matrix,0,sizeof(matrix));
    }//构造函数,定义一个结构体时自动调用 
    void one() {
        matrix[0][0]=1;
        matrix[1][1]=1;
    }//单位矩阵
    node operator*(node other) {
        node ans;//记录乘积
        for(int i=0; i<2; i++)
            for(int j=0; j<2; j++)
                for(int k=0; k<2; k++) {
                    ans.matrix[i][j] += matrix[i][k]*other.matrix[k][j];
                    ans.matrix[i][j]%=mod;
                }
        return ans;
    }//定义了结构体后就会有这个性质   operator是是对*的重载
};
/*
* 相当于p1的一个成员函数
p1*p2相当于对象p1调用函数“operator*”,把对象p2作为一个参数传递给该函数,从而实现了两个对象的相乘。
*/
node power(node a,ll b) {
    node res;
    res.one();//单位矩阵
    while(b) {
        if(b&1)
            res=res*a;
        a=a*a;
        b>>=1;
    }
    return res;
}//快速幂求a的b次方
int main() {
    node temp;//初始矩阵
    temp.matrix[0][0]=1;    //a[2]
    temp.matrix[0][1]=1;    //a[1]
    temp.matrix[1][0]=1;
    temp.matrix[1][1]=0;
    ll n;
    while(~scanf("%lld",&n)) {
    node ans1 = power(temp,n-1);//计算出a[n]
    printf("%lld\n",ans1.matrix[0][0]);
    }
}