矩阵快速幂入门

Powered by:AB_IN 局外人

NEFU459 A Simple Math Problem

这题的矩阵。
矩阵快速幂入门_第1张图片
挂一张比较棒的图。
矩阵快速幂入门_第2张图片

更新后的写法

#include 
using namespace std;
const int MAX = 10;
typedef long long ll;
typedef struct{
    ll m[MAX][MAX];
}Matrix;

Matrix P;//构造出的矩阵

ll k,mod,a[MAX];
Matrix matrixmul(Matrix a,Matrix b) //矩阵乘法
{
    int i,j,k;
    Matrix c;
    for (i = 0 ; i < MAX; i++)
        for (j = 0; j < MAX;j++)
        {
            c.m[i][j] = 0;
            for (k = 0; k < MAX; k++)
                c.m[i][j] =(c.m[i][j]+(a.m[i][k]*b.m[k][j]))%mod;
            c.m[i][j] %=mod;
        }
    return c;
}

Matrix quickpow(Matrix m , ll n)
{
    Matrix b;//单位矩阵在这构造也可以
    for(int i=0;i<MAX;i++)
        for(int j=0;j<MAX;j++)
        {
            if(i==j)b.m[i][j]=1;
            else b.m[i][j]=0;
        }
    while (n >= 1)
    {
        if (n & 1)
                b = matrixmul(b,m);
        n = n >> 1;
        m = matrixmul(m,m);
    }
    return b;
}
int main()
{
    while(cin>>k>>mod){
        for(int i=0;i<MAX;i++){
            cin>>a[i];
            P.m[0][i]=a[i];
            if(i>=1) P.m[i][i-1]=1;
        }
        if(k<10){printf("%lld\n",a[k]%mod);continue;}
        else{
            Matrix tmp=quickpow(P,k-9);
            ll ans=0;
            for(int i=0;i<MAX;i++){
                ans=(ans+tmp.m[0][i]*(9-i)%mod)%mod;
            }
            printf("%lld\n",ans%mod);
        }
    }
    return 0;
}

NEFU461 fibs的位数

广义斐波那契数列。
a n = u ∗ a n − 1 + v ∗ a n − 2 an=u*a_{n−1}+v*a_{n−2} an=uan1+van2
a 0 = a , a 1 = b a_0=a,a_1=b a0=a,a1=b
x = u + u 2 + 4 v 2 , y = u − u 2 + 4 v 2 x=\frac {u+\sqrt{u^2+4v}}2,y=\frac {u-\sqrt{u^2+4v}}2 x=2u+u2+4v ,y=2uu2+4v
a n = ( b − a y ) x n x − y a_n=\frac {(b−ay)x^n} {x−y} an=xy(bay)xn
a n a_n an取对数加一即可:
l e n = n l o g 10 ( x ) + l o g 10 ( b − a y ) − l o g 10 ( x − y ) + 1 len=nlog_{10}(x)+log_{10}(b−ay)−log_{10}(x−y)+1 len=nlog10(x)+log10(bay)log10(xy)+1

#include 
using namespace std;
typedef long long ll;
ll n,a,b,u,v;
int main()
{
    while(scanf("%lld%lld%lld%lld%lld",&n,&a,&b,&u,&v)!=EOF)
    {
        double c=sqrt(u*u+4*v);
        double x=(u+c)/2.0;
        double y=(u-c)/2.0;
        double len=n*log10(x)+log10(b-a*y)-log10(c);
        printf("%lld\n",(ll)len+1);
    }
    return 0;
}

NEFU462 fibs的组合

一开始看这题一点思路都没有,那就先打表!

#include 
const int maxn=100;
using namespace std;

inline int f(int x) {
	if (x == 1 || x == 2) return 1;
	else return f(x - 1) + f(x - 2);
};
int c(int n,int k){
    if (n==k||k==0)
	{
		return 1;
	}
	else
	{
		return c(n-1,k)+c(n-1,k-1);
	}
}
int ans;

int main()
{
    for(int i=1;i<=10;i++){
        ans=0;
        printf("f(%d)=%d   ",i,f(i));
        for(int j=1;j<=i;j++){
            ans+=(f(j)*c(i,j));
        }
        printf("s(%d)=%d\n",i,ans);
    }
    // f(1)=1;f(2)=1;f(3)=2;f(4)=3
    // s(1)=1;s(2)=3;
    return 0;
}

矩阵快速幂入门_第3张图片
观察到 S ( n ) = f ( 2 n ) S(n)=f(2n) S(n)=f(2n)
那就好做多了!找循环节即可!

#include 

using namespace std;
inline int f(int x) {
	if (x == 1 || x == 2) return 1;
	else return f(x - 1) + f(x - 2);
};
int main()
{
    for(int i=1;i<=200;i++){
        if(f(2*i)%8==0)
            cout<<"yes"<<endl;
        else
            cout<<"no"<<endl;
    }
    return 0;
}

在这里插入图片描述
显而易见, 代码孕育而生!

#include 
using namespace std;
typedef long long ll;
ll n,x;
int main()
{
    while(cin>>n){
        x=n%3;
        if(x==1||x==2){
            cout<<"no\n";
        }
        else{
            cout<<"yes\n";
        }
    }
    return 0;
}

NEFU463 Fibs之和

可以推出规律为:
S ( n ) = f ( n + 2 ) − f ( 2 ) S(n)=f(n+2)-f(2) S(n)=f(n+2)f(2)
所以求 a a a b b b的和,就是
S ( b ) − S ( a − 1 ) = f ( b + 2 ) − f ( a + 1 ) S(b)-S(a-1) \\ =f(b+2)-f(a+1) S(b)S(a1)=f(b+2)f(a+1)
代码孕育而生。

#include 
using namespace std;
const int MAX = 2;
const int mod=1000000000;
typedef long long ll;
typedef struct{
    ll m[MAX][MAX];
}Matrix;

Matrix P = {1,1,
            1,0//推出来的矩阵
};
Matrix I = {1,0,//单位阵
            0,1
};

Matrix matrixmul(Matrix a,Matrix b) //矩阵乘法
{
    int i,j,k;
    Matrix c;
    for (i = 0 ; i < MAX; i++)
        for (j = 0; j < MAX;j++)
        {
            c.m[i][j] = 0;
            for (k = 0; k < MAX; k++)
                c.m[i][j] =(c.m[i][j]+(a.m[i][k]*b.m[k][j]))%mod;
            c.m[i][j] %=mod;
        }
    return c;
}

Matrix quickpow(ll n)
{
    Matrix m = P, b = I;
    while (n >= 1)
    {
        if (n & 1)
                b = matrixmul(b,m);
        n = n >> 1;
        m = matrixmul(m,m);
    }
    return b;
}
ll a,b;
int main()
{
    while(cin>>a>>b){
        if(a==0&&b==0)
            break;
        Matrix tmp1,tmp2;
        tmp1=quickpow(a+1);
        tmp2=quickpow(b+2);
        int ans=((tmp2.m[1][0]-tmp1.m[1][0])%mod+(tmp2.m[1][1]-tmp1.m[1][1])%mod)%mod;
        cout<<(ans+mod)%mod<<endl;
        }
    return 0;
}

NEFU457 Not Fibonacci

如果结果是负数可以这么处理(ans+mod)%mod.
f ( n ) = p ∗ f ( n − 1 ) + q ∗ f ( n − 2 ) f(n) = p*f(n - 1) + q*f(n - 2) f(n)=pf(n1)+qf(n2)
f ( 0 ) = a , f ( 1 ) = b f(0) = a, f(1) = b f(0)=a,f(1)=b

记录一下怎么求出来的 n − 1 n-1 n1
{ 1 p q 0 p q 0 1 0 } 1 ∗ { s ( 1 ) f ( 1 ) f ( 0 ) } = { s ( 2 ) f ( 2 ) f ( 1 ) } \left\{ \begin{matrix} 1 & p & q \\ 0 & p & q \\ 0 & 1 & 0 \end{matrix} \right\}^1 *\left\{ \begin{matrix} s(1) \\ f(1) \\ f(0) \end{matrix} \right\} =\left\{ \begin{matrix} s(2) \\ f(2) \\ f(1) \end{matrix} \right\} 100pp1qq01s(1)f(1)f(0)=s(2)f(2)f(1)

  • 首先就是推出上面的这个式子,等号左边只有一列的这个矩阵,一定要出现最小的值,比如 f ( 0 ) f(0) f(0)
  • 然后,推出来的矩阵的1次方,就对应一下等号右边的1,比如 f ( 1 ) f(1) f(1)
  • 然后就可以推出下面的式子了!

{ 1 p q 0 p q 0 1 0 } n ∗ { s ( 1 ) f ( 1 ) f ( 0 ) } = { s ( n + 1 ) f ( n + 1 ) f ( n ) } \left\{ \begin{matrix} 1 & p & q \\ 0 & p & q \\ 0 & 1 & 0 \end{matrix} \right\} ^{n}*\left\{ \begin{matrix} s(1) \\ f(1) \\ f(0) \end{matrix} \right\} =\left\{ \begin{matrix} s(n+1) \\ f(n+1) \\ f(n) \end{matrix} \right\} 100pp1qq0ns(1)f(1)f(0)=s(n+1)f(n+1)f(n)
要求的是 s ( n ) s(n) s(n),把 n n n转换成 n − 1 n-1 n1就行了。
{ 1 p q 0 p q 0 1 0 } n − 1 ∗ { a + b b a } = { s ( n ) f ( n ) f ( n − 1 ) } \left\{ \begin{matrix} 1 & p & q \\ 0 & p & q \\ 0 & 1 & 0 \end{matrix} \right\} ^{n-1}*\left\{ \begin{matrix} a+b \\ b \\ a \end{matrix} \right\} =\left\{ \begin{matrix} s(n) \\ f(n) \\ f(n-1) \end{matrix} \right\} 100pp1qq0n1a+bba=s(n)f(n)f(n1)

#include 
using namespace std;
const int MAX = 3;
const int mod=1e7;
typedef long long ll;
typedef struct{
    ll m[MAX][MAX];
}Matrix;

Matrix P;//构造出的矩阵

Matrix matrixmul(Matrix a,Matrix b) //矩阵乘法
{
    int i,j,k;
    Matrix c;
    for (i = 0 ; i < MAX; i++)
        for (j = 0; j < MAX;j++)
        {
            c.m[i][j] = 0;
            for (k = 0; k < MAX; k++)
                c.m[i][j] =(c.m[i][j]+(a.m[i][k]*b.m[k][j]))%mod;
            c.m[i][j] %=mod;
        }
    return c;
}

Matrix quickpow(Matrix m , ll n)
{
    Matrix b;//单位矩阵在这构造也可以
    for(int i=0;i<MAX;i++)
        for(int j=0;j<MAX;j++)
        {
            if(i==j)b.m[i][j]=1;
            else b.m[i][j]=0;
        }
    while (n >= 1)
    {
        if (n & 1)
                b = matrixmul(b,m);
        n = n >> 1;
        m = matrixmul(m,m);
    }
    return b;
}
ll t,a,b,p,q,s,e,ans1,ans2;
int main()
{
    cin>>t;
    while(t--){
        cin>>a>>b>>p>>q>>s>>e;
        P={1,p,q,0,p,q,0,1,0};
        if(e==0) ans1=a;
        else{
            Matrix tmp=quickpow(P,e-1);
            ans1=(tmp.m[0][0]*(a+b)+tmp.m[0][1]*b+tmp.m[0][2]*a)%mod;
        }
        if(s==0) ans2=0;//为什么这儿是0,不是a呢?因为我们要求的是S(s-1)的值,s如果等于0的话,那么就没有意义了。
        else if(s==1) ans2=a;
        else{
            Matrix tmp=quickpow(P,s-2);
            ans2=(tmp.m[0][0]*(a+b)+tmp.m[0][1]*b+tmp.m[0][2]*a)%mod;
        }
        printf("%lld\n",((ans1-ans2)%mod+mod)%mod);
    }

    return 0;
}

NEFU458 Another kind of Fibonacci

{ 1 1 0 0 0 x 2 y 2 2 x y 0 1 0 0 0 x 0 y } n ∗ { s ( 0 ) f 2 ( 1 ) f 2 ( 0 ) f ( 1 ) f ( 0 ) } = { s ( n ) f 2 ( n + 1 ) f 2 ( n ) f ( n + 1 ) f ( n ) } \left\{ \begin{matrix} 1 & 1 & 0 &0 \\ 0 & x^2 & y^2 &2xy \\ 0 & 1 & 0 &0 \\ 0 & x &0 &y \end{matrix} \right\} ^{n}*\left\{ \begin{matrix} s(0) \\ f^2(1) \\ f^2(0) \\ f(1)f(0) \end{matrix} \right\}=\left\{ \begin{matrix} s(n) \\ f^2(n+1) \\ f^2(n) \\ f(n+1)f(n) \end{matrix} \right\} 10001x21x0y20002xy0yns(0)f2(1)f2(0)f(1)f(0)=s(n)f2(n+1)f2(n)f(n+1)f(n)

#include 
using namespace std;
const int MAX = 4;
const int mod=10007;
typedef long long ll;
typedef struct{
    ll m[MAX][MAX];
}Matrix;

Matrix P;//构造出的矩阵

Matrix matrixmul(Matrix a,Matrix b) //矩阵乘法
{
    int i,j,k;
    Matrix c;
    for (i = 0 ; i < MAX; i++)
        for (j = 0; j < MAX;j++)
        {
            c.m[i][j] = 0;
            for (k = 0; k < MAX; k++)
                c.m[i][j] =(c.m[i][j]+(a.m[i][k]*b.m[k][j]))%mod;
            c.m[i][j] %=mod;
        }
    return c;
}

Matrix quickpow(Matrix m , ll n)
{
    Matrix b;//单位矩阵在这构造也可以
    for(int i=0;i<MAX;i++)
        for(int j=0;j<MAX;j++)
        {
            if(i==j)b.m[i][j]=1;
            else b.m[i][j]=0;
        }
    while (n >= 1)
    {
        if (n & 1)
                b = matrixmul(b,m);
        n = n >> 1;
        m = matrixmul(m,m);
    }
    return b;
}
ll n,x,y,ans;
int main()
{
    while(cin>>n>>x>>y){
        ans=0;
        ll x_2=(x*x)%mod;
        ll y_2=(y*y)%mod;
        ll xy=(2*x*y)%mod;
        P={1,1,0,0,
           0,x_2,y_2,xy,
           0,1,0,0,
           0,x,0,y};
        Matrix tmp=quickpow(P,n);
        for(int i=0;i<4;i++){
            ans=(ans+tmp.m[0][i])%mod;
        }
        printf("%lld\n",ans%mod);
    }
    return 0;
}

完结。

你可能感兴趣的:(ACM,线性代数,矩阵乘法)