加载中...

快速幂矩阵 难在构造

void mul(int c[], int a[], int b[][N])//a*b=c a是行向量 b是矩阵 
{
    int temp[N] = {0};//缓存矩阵 因为mul传入的c矩阵和a矩阵 可能是相同的 你不能一边读一边改
    for (int i = 0; i < N; i ++ )
        for (int j = 0; j < N; j ++ )
            temp[i] = (temp[i] + (LL)a[j] * b[j][i]) % m;

    memcpy(c, temp, sizeof temp);//只能用局部变量
}

void mul(int c[][N], int a[][N], int b[][N])//矩阵乘矩阵
{
    int temp[N][N] = {0};//缓存矩阵 因为mul传入的c矩阵和a矩阵 可能是相同的 你不能一边读一边改
    for (int i = 0; i < N; i ++ )//
        for (int j = 0; j < N; j ++ )
            for (int k = 0; k < N; k ++ )
                temp[i][j] = (temp[i][j] + (LL)a[i][k] * b[k][j]) % m;

    memcpy(c, temp, sizeof temp);
}

    while (n)
    {
        if (n & 1) mul(f1, f1, a);  // res = res * a 向量乘矩阵 
        mul(a, a, a);  // a = a * a 矩阵*矩阵
        n >>= 1;
    }

求斐波那且的前n项和sn https://www.acwing.com/activity/content/problem/content/1756/

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>

using namespace std;

typedef long long ll;

const int N = 3;

int n, m;
ll A[N][N] =    // 上述矩阵 A
{
    {2, 0, -1},
    {1, 0, 0},
    {0, 1, 0}
};
ll S[N] = {2, 1, 0}; // 上述矩阵 S(转置)

void multi(ll A[], ll B[][N]) // 计算方阵 B 乘向量 A,并将结果储存在 A 中
{
    ll ans[N] = {0};
    for (int i = 0; i < N; i ++ )
        for (int j = 0; j < N; j ++ )
            ans[i] += A[j] * B[i][j] % m;
    for (int i = 0; i < N; i ++ )
        A[i] = ans[i] % m;
}

void multi(ll A[][N], ll B[][N]) // 计算方阵 A * B,并将结果储存在 A 中
{
    ll ans[N][N] = {0};
    for (int i = 0; i < N; i ++ )
        for (int j = 0; j < N; j ++ )
            for (int k = 0; k < N; k ++ )
                ans[i][j] += A[i][k] * B[k][j] % m;
    for (int i = 0; i < N; i ++ )
        for (int j = 0; j < N; j ++ )
            A[i][j] = ans[i][j] % m;
}

int main()
{
    scanf("%d%d", &n, &m);
    n-=1; //注意这里也要少一项 因为我们去求的是 f1*a^(n-1)
    while (n)        // 矩阵快速幂
    {
        if (n & 1) multi(S, A);
        multi(A, A);
        n >>= 1;
    }

    printf("%lld", (S[2] % m + m) % m);

    return 0;
}

佳佳的斐波那契https://www.acwing.com/activity/content/problem/content/1757/

求1f1+2f2+3f3+4f4....n*fn因为这里的数字不固定 所以换个方法
发现可以用pn-pn-1表示
这里需要 fn fn+1 sn pn+1
pn+1是发现满足某项和下一项相差一个固定矩阵时候可用

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 4;

int n, m;

void mul(int c[][N], int a[][N], int b[][N])  // c = a * b
{
    static int t[N][N];
    memset(t, 0, sizeof t);

    for (int i = 0; i < N; i ++ )
        for (int j = 0; j < N; j ++ )
            for (int k = 0; k < N; k ++ )
                t[i][j] = (t[i][j] + (LL)a[i][k] * b[k][j]) % m;

    memcpy(c, t, sizeof t);
}

int main()
{
    cin >> n >> m;

    // {fn, fn+1, sn, pn}
    // pn = n * sn - tn
    int f1[N][N] = {1, 1, 1, 0};
    int a[N][N] = {
        {0, 1, 0, 0},
        {1, 1, 1, 0},
        {0, 0, 1, 1},
        {0, 0, 0, 1},
    };

    int k = n - 1;

    // 快速幂
    while (k)
    {
        if (k & 1) mul(f1, f1, a);  // f1 = f1 * a
        mul(a, a, a);  // a = a * a
        k >>= 1;
    }

    cout << (((LL)n * f1[0][2] - f1[0][3]) % m + m) % m << endl;

    return 0;
}

posted @ 2022-08-09 00:04  liang302  阅读(20)  评论(0编辑  收藏  举报