矩阵快速幂题集

矩阵快速幂

矩阵必须全部初始化,注意矩阵大小

POJ - 3070

最简单的矩阵快速幂

f[n]=f[n-1]+f[n-2]

ac:

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;

/*
(f(n-1),f(n-2))*(1,1 =(f(n),f(n-1))
                 1,0)

*/

const ll mod=10000;//mod
const int N=2;

struct Matrix{
    ll a[N][N];
    Matrix(){
        memset(a,0,sizeof(a));
    }
};

Matrix mul(Matrix A,Matrix B)
{
    Matrix C;
    for(int i=0;i<N;i++)
        for(int j=0;j<N;j++)
            for(int k=0;k<N;k++)
                C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;

    return C;
}

Matrix pow_mod(Matrix A,ll n)
{
    Matrix B;//原矩阵
    B.a[0][0]=1;
    B.a[0][1]=1;
    while(n)
    {
        if(n&1) B=mul(B,A);
        A=mul(A,A);
        n=n>>1;
    }
    return B;
}

int main()
{
    ll n;
    Matrix G;
    int c[2][2]={1,1,//构造矩阵
                 1,0};
    for(int i=0;i<2;i++)
        for(int j=0;j<2;j++)
            G.a[i][j]=c[i][j];
    while(scanf("%lld",&n)&&n!=-1)
    {
        if(n==0)
            printf("%d\n",0);
        else if(n==1)
            printf("%d\n",1);
        else{
            Matrix res=pow_mod(G,n-2);
            printf("%lld\n",res.a[0][0]);
        }
    }
    return 0;
}

HDU - 5950

f(n)=f(n-1)+2*f(n-2)+n^4

f(1)=a,f(2)=b

(n+1)^4=n^4+4*n^3+6*n^2+4^n+1

构造的矩阵长宽为7*7

 {\{f(n),f(n-1),n^4,n^3,n^2,n,1\}}*\begin{pmatrix} 1 & 1 & 0 & 0 & 0 & 0 & 0 \\ 2 & 0 & 0 & 0 & 0 & 0 & 0 \\ 1 & 0 & 1 & 0 & 0 & 0 & 0 \\ 4 & 0 & 4 & 1 & 0 & 0 & 0 \\ 6 & 0 & 6 & 3 & 1 & 0 & 0 \\ 4 & 0 & 4 & 3 & 2 & 1 & 0 \\ 1 & 0 & 1 & 1 & 1 & 1 & 1 \\ \end{pmatrix}^{n-2}={\{f(n+1),f(n),(n+1)^4,(n+1)^3,(n+1)^2,(n+1),1\}}

ac:

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;

const ll mod=2147493647;
const int N=7;
int aa,bb;

struct Matrix{
    ll a[N][N];
    Matrix(){
        memset(a,0,sizeof(a));
    }
};

Matrix mul(Matrix A,Matrix B)
{
    Matrix C;
    for(int i=0;i<N;i++)
        for(int j=0;j<N;j++)
            for(int k=0;k<N;k++)
                C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;

    return C;
}

Matrix pow_mod(Matrix A,ll n)
{
    Matrix B;
    B.a[0][0]=bb;
    B.a[0][1]=aa;
    B.a[0][2]=16;
    B.a[0][3]=8;
    B.a[0][4]=4;
    B.a[0][5]=2;
    B.a[0][6]=1;
    while(n)
    {
        if(n&1) B=mul(B,A);
        A=mul(A,A);
        n=n>>1;
    }
    return B;
}

int main()
{
    ll t,n;
    Matrix G;
    int c[7][7]={
    1,1,0,0,0,0,0,
    2,0,0,0,0,0,0,
    1,0,1,0,0,0,0,
    4,0,4,1,0,0,0,
    6,0,6,3,1,0,0,
    4,0,4,3,2,1,0,
    1,0,1,1,1,1,1};
    for(int i=0;i<7;i++)
        for(int j=0;j<7;j++)
            G.a[i][j]=c[i][j];
    cin>>t;
    while(t--)
    {
        cin>>n>>aa>>bb;
        if(n==0)
            cout<<0<<endl;
        else if(n==1)
            cout<<aa<<endl;
        else{
            Matrix res=pow_mod(G,n-2);
            cout<<res.a[0][0]%mod<<endl;
        }
    }
    return 0;
}

链接:https://ac.nowcoder.com/acm/contest/221/C
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

令f(n)=2*f(n-1)+3*f(n-2)+n,f(1)=1,f(2)=2
令g(n)=g(n-1)+f(n)+n*n,g(1)=2
告诉你n,输出g(n)的结果,结果对1e9+7取模

 

输入描述:

多组输入,每行一个整数n(1<=n<=1e9),如果输入为0,停止程序。

输出描述:

在一行中输出对应g(n)的值,结果对1e9+7取模。

示例1

输入

1
5
9
456
0

输出

2
193
11956
634021561

说明

多组输入,输入为0时,终止程序

备注:

项数极大,朴素算法无法在规定时间内得出结果

解析:

矩阵快速幂求解:

原矩阵:(g(n-1),f(n),f(n-1),n^2,n,1)

{
    1,0,0,0,0,0,
    1,2,1,0,0,0,
    0,3,0,0,0,0,
    1,0,0,1,0,0,
    0,1,0,2,1,0,
    0,1,0,1,1,1};

=>(g(n),f(n+1),f(n),(n+1)^2,n+1,1)

这里g(n)只与g(n-1)有关,所以构造矩阵要求(n-1)的次方

ac:

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;

const int mod=1e9+7;//mod
const int N=6;//构造矩阵的长宽

struct Matrix{
    ll a[N][N];
    Matrix(){
        memset(a,0,sizeof(a));
    }
};

Matrix mul(Matrix A,Matrix B)
{
    Matrix C;
    for(int i=0;i<N;i++)
        for(int j=0;j<N;j++)
            for(int k=0;k<N;k++)
                C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;

    return C;
}

Matrix pow_mod(Matrix A,ll n)
{
    Matrix B;//原矩阵
    B.a[0][0]=2;
    B.a[0][1]=2;
    B.a[0][2]=1;
    B.a[0][3]=4;
    B.a[0][4]=2;
    B.a[0][5]=1;
    while(n)
    {
        if(n&1) B=mul(B,A);
        A=mul(A,A);
        n=n>>1;
    }
    return B;
}

int main()
{
    int n;
    Matrix G;
    int c[6][6]={
    1,0,0,0,0,0,
    1,2,1,0,0,0,
    0,3,0,0,0,0,
    1,0,0,1,0,0,
    0,1,0,2,1,0,
    0,1,0,1,1,1};//构造矩阵
    for(int i=0;i<N;i++)
        for(int j=0;j<N;j++)
            G.a[i][j]=c[i][j];
    while(scanf("%d",&n)&&n!=0)
    {
        if(n==0)
        {
            printf("0\n");
        }
        else if(n==1)
        {
            printf("2\n");
        }
        else{
            Matrix res=pow_mod(G,n-1);
            printf("%lld\n",res.a[0][0]);
            //printf("%lld\n",res.a[0][2]);
        }
    }
    return 0;
}

链接:https://ac.nowcoder.com/acm/contest/105/G
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

这是一个加强版的斐波那契数列。

给定递推式F(i)=⎧⎪⎨⎪⎩F(i−1)+F(i−2)+i3+i2+i+1i>10i=01i=1F(i)={F(i−1)+F(i−2)+i3+i2+i+1i>10i=01i=1

求F(n)的值,由于这个值可能太大,请对109+7取模。

输入描述:

第一行是一个整数T(1 ≤ T ≤ 1000),表示样例的个数。
以后每个样例一行,是一个整数n(1 ≤ n ≤ 1018)。

输出描述:

每个样例输出一行,一个整数,表示F(n) mod 1000000007。

示例1

输入

4
1
2
3
100

输出

1
16
57
558616258

解析:

直接列出即可

注意B矩阵的构造,n是3

ac:

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;

const ll mod=1e9+7;//mod
const int N=6;//构造矩阵的长宽

struct Matrix{
    ll a[N][N];
    Matrix(){
        memset(a,0,sizeof(a));
    }
};

Matrix mul(Matrix A,Matrix B)
{
    Matrix C;
    for(int i=0;i<N;i++)
        for(int j=0;j<N;j++)
            for(int k=0;k<N;k++)
                C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;

    return C;
}

Matrix pow_mod(Matrix A,ll n)
{
    Matrix B;//原矩阵
    B.a[0][0]=16;
    B.a[0][1]=1;
    B.a[0][2]=27;
    B.a[0][3]=9;
    B.a[0][4]=3;
    B.a[0][5]=1;
    while(n)
    {
        if(n&1) B=mul(B,A);
        A=mul(A,A);
        n=n>>1;
    }
    return B;
}

int main()
{
    ll n,t;
    Matrix G;
    ll c[6][6]={
    1,1,0,0,0,0,
    1,0,0,0,0,0,
    1,0,1,0,0,0,
    1,0,3,1,0,0,
    1,0,3,2,1,0,
    1,0,1,1,1,1,};//构造矩阵
    for(int i=0;i<N;i++)
        for(int j=0;j<N;j++)
            G.a[i][j]=c[i][j];
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&n);
        if(n==0)
        {
            printf("0\n");
        }
        else if(n==1)
        {
            printf("1\n");
        }
        else{
            Matrix res=pow_mod(G,n-2);
            printf("%lld\n",res.a[0][0]);//新矩阵的f[n]的位置
        }
    }
    return 0;
}

E. Product Oriented Recurrence

Product Oriented Recurrence

解析:

f(x)=f(x-1)*f(x-2)*f(x-3)*C^(2*x-6)

给定n,f1,f2,f3,和c求fn

解析:

列出几项后发现

f(n)=f1^a*f2^b*f3^c*c^d

an=a(n-1)+a(n-2)+a(n-3)

bn=b(n-1)+b(n-2)+b(n-3)

cn=c(n-1)+c(n-2)+c(n-3)

dn=d(n-1)+d(n-2)+d(n-3)+2*n-6

我们用四个矩阵快速幂求an,bn,cn,dn

这个式子可以通过四个矩阵快速幂求各系数+欧拉降幂解决

ac:

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;

const ll mod=1000000006;//phi(1000000007)
const ll mod2=1000000007;
const int N=100;
ll x,y,z;

struct Matrix{
    ll a[N][N];
    Matrix(){
        memset(a,0,sizeof(a));
    }
};

Matrix mul(Matrix A,Matrix B,int sz)
{
    Matrix C;
    for(int i=0;i<sz;i++)
        for(int j=0;j<sz;j++)
            for(int k=0;k<sz;k++)
                C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
    return C;
}

Matrix pow_mod(Matrix B,Matrix A,ll n,int sz)
{
    while(n)
    {
        if(n&1) B=mul(B,A,sz);
        A=mul(A,A,sz);
        n=n>>1;
    }
    return B;
}

ll qpow(ll a,ll b)
{
    ll ans=1;
    a=a%mod2;
    while(b)
    {
        if(b&1) ans=(ans*a)%mod2;
        a=(a*a)%mod2;
        b>>=1;
    }
    return ans;
}

int main()
{
    ll n,k;
    Matrix G;
    ll cc[3][3]={
    1,1,0,
    1,0,1,
    1,0,0};
    for(int i=0;i<N;i++)
        for(int j=0;j<N;j++)
            G.a[i][j]=cc[i][j];

    ll dd[5][5]={
    1,1,0,0,0,
    1,0,1,0,0,
    1,0,0,0,0,
    2,0,0,1,0,
    -6,0,0,1,1};
    Matrix H;
    for(int i=0;i<5;i++)
        for(int j=0;j<5;j++)
            H.a[i][j]=dd[i][j];

    cin>>n>>x>>y>>z>>k;
    Matrix A,B,C,D;

    A.a[0][0]=2,A.a[0][1]=1,A.a[0][2]=1;
    B.a[0][0]=3,B.a[0][1]=2,B.a[0][2]=1;
    C.a[0][0]=4,C.a[0][1]=2,C.a[0][2]=1;
    D.a[0][0]=14,D.a[0][1]=6,D.a[0][2]=2,D.a[0][3]=7,D.a[0][4]=1;

    A=pow_mod(A,G,n-4,3);
    B=pow_mod(B,G,n-4,3);
    C=pow_mod(C,G,n-4,3);
    D=pow_mod(D,H,n-4,5);
    ll va=A.a[0][2];
    ll vb=B.a[0][2];
    ll vc=C.a[0][2];
    ll vd=D.a[0][2];

    /*
    a^b=a^(b%phi(mod)+phi(mod))%mod
    这里要欧拉降幂,前面的阶乘x,x=x%phi(mod),phi(1000000007)=1000000006
    所以前面用的是mod=1000000006;
    后面求pow用mod;
    */

    ll x1=qpow(x,va+mod);
    ll x2=qpow(y,vb+mod);
    ll x3=qpow(z,vc+mod);
    ll x4=qpow(k,vd+mod);
    ll sum=(x1*x2)%mod2;
    sum=(sum*x3)%mod2;
    sum=(sum*x4)%mod2;
    printf("%lld\n",sum);
    return 0;
}

https://ac.nowcoder.com/acm/contest/885/B

题意:

求指数非常大(大数)的矩阵快速幂,用10进制暴力计算,预处理0-9的情况

ac:

#include <bits/stdc++.h>
#define N 2
using namespace std;
typedef long long ll;
const int maxn = 1e6+5;
char n[maxn];
ll Mod;
ll x0,x1,a,b;
int len;
ll cnt=0;
struct matrix
{
    ll a[N+1][N+1];
    friend matrix operator*(matrix A,matrix B)
    {
        matrix C;
        for(int i=0;i<N;i++){
            for(int j=0;j<N;j++){
                C.a[i][j]=0;
                for(int k=0;k<N;k++){
                    C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%Mod;
                }
            }
        }
        return C;
    }
}p[31];


matrix qpow(matrix A,int m)//方阵A的m次幂
{
    matrix ans;//单位矩阵
    for(int i=0;i<N;i++)
        for(int j=0;j<N;j++)
            ans.a[i][j]=(i==j);
    while(m)
    {
        if(m&1) ans=ans*A;
        A=A*A;
        m>>=1;
    }
    return ans;
}

matrix ppow(matrix x,char *b)
{
    len = strlen(b);
    matrix ans,A,res;
    ans.a[0][0] = x1,ans.a[0][1] = x0;
    A.a[0][0]=A.a[1][1]=1;
    int sub = 0;
    res=qpow(x,b[0]-'0'-1);
    for(int i=1;i<len;i++)
    {
        res=qpow(res,10);
        int m=b[i]-'0'+9;
        //matrix tmp=qpow(x,m);预处理,加速
        res=res*p[m];
    }
    ans=ans*res;
    return ans;
}

matrix init()
{
    matrix f;
    f.a[0][0] = a; f.a[0][1] = 1;
    f.a[1][0] = b; f.a[1][1] = 0;
    p[1]=f;
    for(int i=2;i<=21;i++)
        p[i]=p[i-1]*f;
    return f;
}

int main()
{
    scanf("%lld%lld%lld%lld",&x0,&x1,&a,&b);
    scanf("%s%lld",n+1,&Mod);
    matrix f=init();
    matrix ans = ppow(f,n+1);
    printf("%lld\n",ans.a[0][0]);
}

https://vjudge.net/problem/POJ-3233

题意:

给定一个矩阵A,求A+A^2+A^3+A^4+...+A^n

解析:

=>

=>

我们发现规律

|A  ,  1|                         |A^n , 1+A^1+A^2+....+A^(n-1)|

|0  ,  1|  的n次方等于   |0     ,                   1                   |

我们直接构造一个长宽为2n的矩阵A',将矩阵分成4份,左上为A,右上,右下为单位矩阵

然后求pow(A',k),输出右上部分(a[i][j]-1+m)%m的结果

ac:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define ll long long
#define N 101
using namespace std;
ll mod;
int sz;

struct matrix
{
    ll a[N+1][N+1];
    friend matrix operator*(matrix A,matrix B)
    {
        matrix C;
        for(int i=0;i<sz;i++){
            for(int j=0;j<sz;j++){
                C.a[i][j]=0;
                for(int k=0;k<sz;k++){
                    C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
                }
            }
        }
        return C;
    }
};

matrix qpow(matrix A,ll m)//方阵A的m次幂
{
    matrix ans;//单位矩阵
    for(int i=0;i<sz;i++)
        ans.a[i][i]=1;
    while(m)
    {
        if(m&1) ans=ans*A;
        A=A*A;
        m>>=1;
    }
    return ans;
}

int main()
{
    ll n,k,m;
    scanf("%lld%lld%lld",&n,&k,&m);
    mod=m;
    sz=n*2;
    matrix A;
    for(int i=0;i<sz;i++)
        for(int j=0;j<sz;j++)
            A.a[i][j]=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
            scanf("%lld",&A.a[i][j]);
        A.a[i][i+n]=A.a[i+n][i+n]=1;
    }

    A=A*qpow(A,k);
    for(int i=0;i<n;i++)
        A.a[i][i+n]=(A.a[i][i+n]-1+m)%m;

    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            printf("%lld",A.a[i][j+n]);
            printf("%s",j<n-1?" ":"\n");
        }
    }
    return 0;
}

/*
3 99999 4
1 2 3
4 5 6
7 8 9
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值