矩阵快速幂模板

矩阵快速幂是建立在快速幂基础上的。

其实就是快速幂的底数变成了矩阵

 

快速幂算法我就不多说了,下面是矩阵快速幂的解释。

这个是快速幂+快速幂取模的模板,结构体的重载乘号

struct mat
{
    int m[maxn][maxn];
}unit;

mat operator * (mat a, mat b)
{
    mat ans;
    ll x;
    for(int i = 0; i < n; ++i)
        for(int j = 0; j < n; ++j)
        {
            x = 0;
            for(int k = 0; k < n; ++k)
                x += ((ll)a.m[i][k]*b.m[k][j])%mod;
            ans.m[i][j] = x%mod;
        }
        return ans; //返回的是一个矩阵
}

void init_unit()
{
    for(int i = 0; i < maxn; ++i) unit.m[i][i] = 1; //初始化单位矩阵
}

mat poww(mat a, ll b)
{
    mat ans = unit;
    mat base = a;
    while(b)
    {
        if(b&1)
            ans = ans*base;
        base = base*base;
        b >>= 1;
    }
    return ans;
}

解释其实也没什么可以解释的。。就是快速幂从数变成了矩阵,初始化的时候用的是单位矩阵

下面给一个例题

hdu 1575

#include <iostream>
#include <string.h>
#include <cstdio>
#define ll long long
#define mod(x) ((x)%9973)

using namespace std;
int n;
const int mod = 9973;
const int maxn = 15;

struct mat
{
    int m[maxn][maxn];
}unit;

mat operator * (mat a, mat b)
{
    mat ans;
    ll x;
    for(int i = 0; i < n; ++i)
        for(int j = 0; j < n; ++j)
        {
            x = 0;
            for(int k = 0; k < n; ++k)
                x += ((ll)a.m[i][k]*b.m[k][j])%mod;
            ans.m[i][j] = x%mod;
        }
        return ans; //返回的是一个矩阵
}

void init_unit()
{
    for(int i = 0; i < maxn; ++i) unit.m[i][i] = 1; //初始化单位矩阵
}

mat poww(mat a, ll b)
{
    mat ans = unit;
    mat base = a;
    while(b)
    {
        if(b&1)
            ans = ans*base;
        base = base*base;
        b >>= 1;
    }
    return ans;
}

int main()
{
    int T; scanf("%d", &T);
    init_unit();
    while(T--)
    {
        ll k;
        mat a;
        scanf("%d%lld", &n, &k);
        for(int i = 0; i < n; ++i)
            for(int j = 0; j < n; ++j)
                scanf("%d", &a.m[i][j]);
        a = poww(a, k);
        ll ans = 0;
        for(int i = 0; i < n; ++i) ans += a.m[i][i];
        printf("%lld\n", ans%mod);
    }
    return 0;
}

 

下面是矩阵快速幂打Fibonacci数列的例子,具体原理就不多说了,推一下就知道了

#include <iostream>
#include <cstdio>
#define ll long long

using namespace std;
const int MX = 4;
const int mod = 10000;
ll n;

struct mat
{
    ll m[MX][MX];
}unit;

void unit_init()
{
    for(int i = 0; i < MX; ++i) unit.m[i][i] = 1;
}

mat operator * (mat a, mat b)
{
    mat ans;
    ll x;
    for(int i = 0; i < 2; ++i)
        for(int j = 0; j < 2; ++j)
        {
            x = 0;
            for(int k = 0; k < 2; ++k)
                x += (a.m[i][k]*b.m[k][j])%mod;
            ans.m[i][j] = x%mod;
        }
    return ans;
}

mat poww(mat a, ll b)
{
    mat ans = unit, base = a;
    while(b)
    {
        if(b&1)
            ans = ans*base;
        base = base*base;
        b >>= 1;
    }
    return ans;
}

int main()
{
    unit_init();
    while(scanf("%lld", &n) != EOF && n != -1)
    {
        mat a;
        a.m[0][0] = 1; a.m[0][1] = 1;
        a.m[1][0] = 1; a.m[1][1] = 0; // a = (1,1,1,0)
        mat ansmat = poww(a, n);
        ll ans = ansmat.m[0][1];
        printf("%lld\n", ans);
    }
    return 0;
}

 

posted @ 2019-08-16 02:09  mpeter  阅读(69)  评论(0)    收藏  举报