(矩阵)快速幂||取余运算

今天看了一下cgy杯,里面涉及的算法很多,其中有一个就是在蓝桥杯,校赛等多次比赛中坑了我的矩阵快速幂,然而我现在还不会,毕竟已经学了线代,今天把它总结一下叭。
 

1.快速幂

解释

首先,快速幂的目的就是做到快速求幂,假设我们要求a^b,按照朴素算法就是把a连乘b次,这样一来时间复杂度是O(b)也即是O(n)级别,快速幂能做到O(logn),快了好多好多。它的原理如下:

假设我们要求a^b ,那么其实b是可以拆成二进制的,该二进制数第i位的权为2^(i-1) 例如当b==11时a11=a(2^0 + 2^1+ 2^3) ,11的二进制是1011,11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1,因此,我们将a¹¹转化为算 a2^0* a2^1* a2^3,也就是a1* a2* a8 ,看出来快的多了吧原来算11次,现在算三次,但是这三项貌似不好求的样子....不急,下面会有详细解释。

**由于是二进制,很自然地想到用位运算这个强大的工具:&和>> &运算通常用于二进制取位操作,例如一个数 & 1 的结果就是取二进制的最末位。还可以判断奇偶x&1==0为偶,x&1==1为奇。 >>运算比较单纯,二进制去掉最后一位,不多说了,先放代码再解释。 **

模板

int quickPower(int a, int b)//是求a的b次方
{
    int ans = 1, base = a;//ans为答案,base为a^(2^n)
    while(b > 0)//b是一个变化的二进制数,如果还没有用完,也可以改成while(b)
   {
        if(b & 1)//&是位运算,b&1表示b在二进制下最后一位是不是1,如果是:
            ans *= base;//把ans乘上对应的a^(2^n)

        base *= base;//base自乘,由a^(2^n)变成a^(2^(n+1))
        b >>= 1;
//位运算,b右移一位,如101变成10(把最右边的1移掉了),10010变成1001。现在b在二进制下最后一位是刚刚的倒数第二位。结合上面b & 1食用更佳
    }
    return ans;
}

实现

#include 
using namespace std;
long long int k;
long long int quickPower(long long int a,long long int b)
{
    long long int ans=1,base=a;
    while(b>0)
    {
        if(b&1)
            ans=ans*base%k;
        base=base*base%k;
        b>>=1;
    }
    return ans;
    }

int main()
{
    long long int b,p;
    cin>>b>>p>>k;
    printf("%lld^%lld mod %lld=%d",b,p,k,quickPower(b,p)%k);
    return 0;
}

 

2.模板【矩阵快速幂】

#include 
using namespace std;
#define mod 1000000007
#define ll long long
//结构体矩阵 
struct matric{
        ll m[101][101];
};
matric a,e;//a是输入矩阵,e是单位阵
ll n,p;
//矩阵乘法 
matric Multi(matric x,matric y){
    matric c;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            c.m[i][j]=0;
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
                c.m[i][j]=c.m[i][j]%mod+x.m[i][k]*y.m[k][j]%mod;
    return c;
} 

//矩阵快速幂 
matric pow(matric x,ll y){
    matric ans=e;
    while(y){
        if(y&1)
            ans=Multi(ans,x);
        x=Multi(x,x);
        y>>=1;
    }
    return ans;
} 

int main()
{
    cin>>n>>p;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            cin>>a.m[i][j];
    for(int i=1;i<=n;i++)
        e.m[i][i]=1;
    matric ans=pow(a,p);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)
            cout<

 
 

3.Fibonacci

Emmm 如何应用到斐波那契捏
只要第一步确定了它最初的数列是怎么样的就行了

//#include 
#include 
#include 
using namespace std;
#define mod 10000
#define ll long long
//结构体矩阵 
struct matric{
    ll m[3][3];
};
matric a,e;//a是输入矩阵,e是单位阵
ll n=2,p;
//矩阵乘法 
matric Multi(matric x,matric y){
    matric c;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
                c.m[i][j]=0;
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
                c.m[i][j]=c.m[i][j]%mod+x.m[i][k]*y.m[k][j]%mod;
    return c;
} 

//矩阵快速幂 
matric pow(matric x,ll y){
    matric ans=e;
    while(y){
        if(y&1)
            ans=Multi(ans,x);
        x=Multi(x,x);
        y>>=1;
    }
    return ans;
} 

int main()
{
    while(cin>>p&&p!=-1){
    a.m[1][1]=a.m[2][1]=a.m[1][2]=1;
    a.m[2][2]=0;
    for(int i=1;i<=n;i++)
        e.m[i][i]=1;
    matric ans=pow(a,p);
    cout<

 
 

4.CGY杯

CGYtql

#include 
using namespace std;

typedef long long ll;

const int mod=1e9+7;
int f[6]={0,8,6,5,3,2};
struct matric{
    ll m[6][6];
};
matric a,e;//input a,danwei e
//矩阵乘法

matric Multi(matric x,matric y){
    matric c;
    for(int i=1;i<=5;i++)
        for(int j=1;j<=5;j++)
            c.m[i][j]=0;
    for(int i=1;i<=5;i++)
        for(int j=1;j<=5;j++)
            for(int k=1;k<=5;k++){
                c.m[i][j]=c.m[i][j]%mod+x.m[i][k]*y.m[k][j]%mod;
            }
    return c;
}
//矩阵快速幂
matric pow(matric x,ll y){
    matric ans=e;
    while(y){
        if(y&1)
            ans=Multi(ans,x);
        x=Multi(x,x);
        y>>=1;
    }

    return ans;
}

int main(){
    int n;
    for(int i=1;i<=5;i++)
        e.m[i][i]=1;
    while(cin>>n&&n!=0){
       // memset(a,0,sizeof(a));
        int ans1=0;
        int ans2=0;
        if(n<6){
            cout<

修订过后

注意longlong

#include 
#include  
    using namespace std;

    typedef long long ll;

    const int mod=1e9+7;
    int f[6]={0,8,6,5,3,2};
    struct matric{
        ll m[6][6];
    };
    matric a,e;//input a,danwei e
    //矩阵乘法

    matric Multi(matric x,matric y){
        matric c;
        for(int i=1;i<=5;i++)
            for(int j=1;j<=5;j++)
                c.m[i][j]=0;
        for(int i=1;i<=5;i++)
            for(int j=1;j<=5;j++)
               for(int k=1;k<=5;k++){
                    c.m[i][k]=(c.m[i][k]%mod+x.m[i][j]*y.m[j][k]%mod)%mod;
                }
        return c;
    }
    //矩阵快速幂
    matric pow(matric x,ll y){
       matric ans=e;
        while(y){
            if(y&1)
                ans=Multi(ans,x);
            x=Multi(x,x);
            y>>=1;
        }

        return ans;
    }

    int main(){
        long long int n;
        for(int i=1;i<=5;i++)
            e.m[i][i]=1;
        while(cin>>n&&n!=0){
           // memset(a,0,sizeof(a));
            long long int ans1=0;
            long long int ans2=0;
            if(n<6){
                cout<

这个代码可以使res初始化为零矩阵

 Matrix operator * (const Matrix &a){
    Matrix res;
    for(int i=1;i<=5;i++)
        for(int j=1;j<=5;j++)
            for(int k=1;k<=5;k++)
                res.m[i][k]=(res.m[i][k]+(m[i][j]*a.m[j][k])%mod)%mod;
    return res;
  }

 
 

5.Kiki & Little Kiki 2

有题目可知,如果左边的灯是开的,则这个灯的状态就要改变,从而可以找出一个规律a[n]=(a[n-1]+a[n])%2, a[1]=(a[1]+a[n])%2

A= \left\{ \begin{matrix} 1 & 0 & 0 & \cdots & 0 & 1\\ 1 & 1 & 0 & \cdots & 0 & 0 \\ 0 & 1 & 1 & \cdots & 0 & 0 \\ \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & 0 & \cdots & 1 & 0 \\ 0 & 0 & 0 & \cdots & 1 & 1 \\ \end{matrix} \right\}

#include
#include
#include
#include
#define ll long long
using namespace std;
int m,num,sum[101];

struct matric{
    int n[101][101];
};
matric e,a,b;//a is 初始 , b is input
matric Multi(matric x,matric y){
    matric c;
    for(int i=1;i<=num;i++)
        for(int j=1;j<=num;j++)
            c.n[i][j]=0;
    for(int i=1;i<=num;i++)
        for(int j=1;j<=num;j++)
            for(int k=1;k<=num;k++)
                c.n[i][j]=(c.n[i][j]+x.n[i][k]*y.n[k][j])%2;
    return c;
}

//quick
matric pow(matric x,int y){//y is time
    matric ans=e;
    while(y){
        if(y&1)
            ans=Multi(ans,x);
        x=Multi(x,x);
        y>>=1;
    }
    return ans;
}

int main(){
    //freopen("data","r",stdin);
    char ch[101];

    while(cin>>m){
        scanf("%s",ch);
                num=strlen(ch);
                memset(b.n,0,sizeof(b.n));
                memset(a.n,0,sizeof(a.n));
            for(int i=1;i<=num;i++){
            b.n[i][1]=ch[i-1]-'0';
        }

                for(int i=1;i<=num;i++){
            e.n[i][i]=1;
        }

        a.n[1][1]=a.n[1][num]=1;
        for(int i=2;i<=num;i++)
            a.n[i][i-1]=a.n[i][i]=1;

        matric ans=pow(a,m);
        ans=Multi(ans,b);
        for(int i=1;i<=num;i++)
        {
                      cout<
  • 这里由于没有memset导致输出错误;
  • y>>=1;这里总是会少了=;
  • b.n[i][1]=ch[i-1]-'0';傻傻的跟着别人把写成了0;

 
 

6.G-又见斐波那契

递推公式

将输入的n+1后进行观察取系数
f[i+1] = f[i] + f[i--1] + i^3 + i^2 + i + 1
f[i] = f[i]
(i+1)^3 = i^3 + 3i^2 + 3i + 1
(i+1)^2 = i^2 + 2*i + 1
(i+1) = i + 1
1 = 1
因此在最后带进去的实参是n-1;

#include
#include
#include
#include
#define ll long long
#define mod 1000000007
using namespace std;
ll m,num;

ll a[7][7]={
0,0,0,0,0,0,0,
0,1,1,1,1,1,1,
0,1,0,0,0,0,0,
0,0,0,1,3,3,1,
0,0,0,0,1,2,1,
0,0,0,0,0,1,1,
0,0,0,0,0,0,1
};

struct matric{
    ll n[7][7];
};
matric e,b;//a is 初始 , b is input
matric Multi(matric x,matric y){
    matric c;
    for(int i=1;i<=6;i++)
        for(int j=1;j<=6;j++)
            c.n[i][j]=0;
    for(int i=1;i<=6;i++)
        for(int j=1;j<=6;j++)
            for(int k=1;k<=6;k++)
                c.n[i][j]=(c.n[i][j]+x.n[i][k]*y.n[k][j])%mod;
    return c;
}

//quick
matric pow(matric x,ll y){//y is time
    matric ans=e;
    while(y){
        if(y&1)
            ans=Multi(ans,x);
        x=Multi(x,x);
        y>>=1;
    }
    return ans;
}

int main(){
    //freopen("data","r",stdin);
    int T;

    cin>>T;
    matric base;
    base.n[1][1]=1,base.n[2][1]=0,base.n[3][1]=8;
    base.n[4][1]=4,base.n[5][1]=2,base.n[6][1]=1;
    for(int i=1;i<=6;i++)
        e.n[i][i]=1;
    for(int i=1;i<=6;i++)
        for(int j=1;j<=6;j++)
            b.n[i][j]=a[i][j];

    while(T--){
        cin>>num;
        matric ans = pow(b,num-1);
        ans=Multi(ans,base);
        cout<

你可能感兴趣的:((矩阵)快速幂||取余运算)