首页 > 其他分享 >快速幂 矩阵快速幂题解

快速幂 矩阵快速幂题解

时间:2022-12-27 20:55:09浏览次数:46  
标签:matrix int 题解 ll ans 矩阵 ++ res 快速

目录

快速幂 矩阵快速幂练习题题解12.28

HDU 1061

题意:给定T组数据,接下来T行有T个数,求N的N次方的个位数的值

注意:因为只求个位数,所以对个位进行快速幂就可以了

思路:一直累乘的话,N的范围是0 ~ 1e9,显然一个N就要运行乘法1e9次,时间复杂度为O(T * N),显然会TLE,所以就用到了快速幂,把O(T * N)优化到O(T * logn)

代码如下:

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        long long n;
        cin >> n;
        long long x = n,ans = 1;
        while(n)
        {
            if(n % 2 == 1) ans *= x;
            x *= x;
            ans %= 10;
            x %= 10;
            n >>= 1;
        }
        cout << ans << endl;
    }
    return 0;
}

HDU 1575

题意:有T组数据,每组数据给定一个n和k,接下来n行是A这个方阵的各个元素,求A的k次方的方阵的迹

思路:显然用矩阵乘法累乘的时间复杂度为O(T * k),所以要降为O(T * logk),套用矩阵快速幂就可以了

代码如下:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n,k;
const int N = 20,mod = 9973;
ll a[N][N],ans[N][N];

int Tr() // 求矩阵的迹
{
    int sum = 0;
    for(int i = 0; i < n; i++)
    {
        sum += ans[i][i];
        sum %= mod;
    }
    return sum;
}

void f1() // 余1时的操作
{
    ll c[N][N] = {0};
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {
            for(int t = 0; t < n; t++)
            {
                c[i][j] += ans[i][t] * a[t][j] % mod;
            }
        }
    }
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {
            ans[i][j] = c[i][j];
        }
    }
}

void f2() // 余0时的操作
{
    ll c[N][N] = {0};
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {
            for(int t = 0; t < n; t++)
            {
                c[i][j] += a[i][t] * a[t][j] % mod;
            }
        }
    }
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {
            a[i][j] = c[i][j];
        }
    }
}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin >> n >> k;
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < n; j++)
            {
                cin >> a[i][j];
            }
        }

        memset(ans,0,sizeof(ans));
        for(int i = 0; i < n; i++) ans[i][i] = 1;

        while(k)
        {
            if(k & 1) f1();
            f2();
            k >>= 1;
        }

        cout << Tr() << endl;
    }
    return 0;
}

HDU 2035

题意:给定a和b,求a的b次方的后三位表示的数

思路:同样是要优化时间复杂度,套用快速幂就可以了

代码如下:

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int a,b;
    while(cin >> a >> b)
    {
        if(a == 0 && b == 0) break;
        int ans = 1;
        while(b)
        {
            if(b & 1) ans *= a;
            a *= a;
            a %= 1000;
            ans %= 1000;
            b >>= 1;
        }
        cout << ans << endl;;
    }
    return 0;
}

HDU 5015

题意:给定n,m两个数,再给出矩阵第一列的n个元素,矩阵中第一行元素为{0,233,2333,...},矩阵中有a[i][j] = a[i - 1][j] + a[i][j - 1],求a[n][m]的值

注意:数组下标是从0开始的,所以数组大小应该是(n + 1) * (m + 1)

思路:因为第一行的元素是{0,233,2333,...},且根据a[i][j] = a[i - 1][j] + a[i][j - 1],数组中a[0][0]元素的数值并不影响我们求a[n][m],所以我们可以设a[0][0]为23,这样我们第一行元素就可以用a[0][i] = a[0][i - 1] * 10 + 3这条式子求得,其中i >= 1。

可以根据a[i][j] = a[i - 1][j] + a[i][j - 1]推导得到

所以就可以求得a[i][j]=a[i][j−1]+a[i−1][j−1]+a[i−2][j−1]+...+a[2][j−1]+a[1][j−1]+10∗a[0][j−1]+3

然后就可以发现我们要求的a[n][m]所在的第m列的元素可以如下图求出

一步步逆推,可得出我们只需要将一个行列数都为n + 2的方阵不断累乘m次就可以得到我们最后需要的上图中左边这个矩阵,再将其中第n + 1行乘上给定的列矩阵就可以得到一个数,就是我们的答案了

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;


struct matrix {
    int N;
    ll a[15][15];
    matrix(int N_) //初始化单位矩阵
    {
        N = N_;
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                a[i][j] = 0;
            }
        }
    }
    matrix matrix_mul(matrix A, matrix B, ll mod)
    {   // 2个矩阵相乘
        matrix C(A.N);
        for (int i = 0; i < A.N; i++)
        {
            for (int j = 0; j < A.N; j++)
            {
                C.a[i][j] = 0;
                for (int k = 0; k < A.N; k++)
                {
                    C.a[i][j] = (C.a[i][j] + A.a[i][k] * B.a[k][j] % mod) % mod;
                }
            }
        }
        return C;
    }
    matrix unit(ll n)// 返回一个大小为n×n的单位矩阵
    {
        matrix res(n);
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (i == j) res.a[i][j] = 1;
                else res.a[i][j] = 0;
            }
        }
        return res;
    }
    matrix matrix_pow(matrix A, ll n, ll mod) // 矩阵快速幂
    {
        matrix res = unit(A.N);
        while (n > 0)
        {
            if (n & 1)                         
                res = matrix_mul(res, A, mod); 
            A = matrix_mul(A, A, mod);         
            n >>= 1;                           
        }
        return res;
    }
    matrix matrix_sum(int n, ll mod)
    {
        matrix res(N * 2);
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                res.a[i][j] = a[i][j];
            }
        }
        //右上角为单位矩阵
        for (int i = 0; i < N; i++)
        {
            for (int j = N; j < 2 * N; j++)
            {
                if (i == j - N) res.a[i][j] = 1;
                else res.a[i][j] = 0;
            }
        }
        //左下角为0矩阵
        for (int i = N; i < 2 * N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                res.a[i][j] = 0;
            }
        }
        //右下角为单位矩阵
        for (int i = N; i < 2 * N; i++)
        {
            for (int j = N; j < 2 * N; j++)
            {
                if (i == j) res.a[i][j] = 1;
                else res.a[i][j] = 0;
            }
        }
        res = matrix_pow(res, n + 1, mod);
        matrix ans(N);
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                ans.a[i][j] = res.a[i][j + N];
            }
        }
        return ans;
    }
    void print() //显示矩阵全部元素
    {
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                cout << a[i][j] << " ";
            }
            cout << endl;
        }

    }
};
ll mod = 10000007;
ll p[11]; // 第一列元素

int main()
{
    int n;
    ll m;
    while (cin >> n >> m)
    {
        for (int i = 1; i <= n; i++)
        {
            cin >> p[i];
        }
        p[0] = 23;
        p[n + 1] = 3;
        matrix A(n + 2);
        for (int i = 0; i <= n; i++)
        {
            A.a[i][0] = 10;
            A.a[i][n + 1] = 1;
        }
        A.a[n + 1][n + 1] = 1;
        for (int i = 1; i <= n; i++) // 下三角矩阵
        {
            for (int j = 1; j <= i; j++)
            {
                A.a[i][j] = 1;
            }
        }
        A = A.matrix_pow(A, m, mod);
        ll ans = 0;
        for (int i = 0; i <= n + 1; i++)
        {
            ans += A.a[n][i] * p[i];
            ans %= mod;
        }
        cout << ans << endl;
    }
	return 0;
}

HDU 6198

题意:找出不能由k个斐波那契数构成的最小数

思路:打表找规律

k 结果
1 4
2 12
3 33
…… ……

由此可以看出答案是F(2 * k + 3) - 1,又因为k的数据范围过大,递归求斐波那契数列的时间复杂度为O(2^n),无法直接求得斐波那契数列的值,所以用矩阵来求斐波那契数列的值

注意:可以搜一下如何利用矩阵求得斐波那契数列

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod = 998244353;

struct Matrix {
    ll n = 2,m = 2;
	ll v[2][2];
    void init()
    {
        memset(v,0,sizeof(v));
    }
};

Matrix Matrix_mul(Matrix &a,Matrix &b)
{
    Matrix res;
    res.init();
    for (int i = 0; i < a.n; i++)
		for (int j = 0; j < b.m; j++)
			for (int k = 0; k < a.m; k++)
				res.v[i][j] = (a.v[i][k] * b.v[k][j] % mod + res.v[i][j]) % mod;
	return res;
}
ll _pow(Matrix &a,int n)
{
    Matrix res;
    res.init();
    for(int i = 0; i < 2; i++)
    {
        for(int j = 0; j < 2; j++)
        {
            res.v[i][j] = 1;
        }
    }
    while(n)
    {
        if(n & 1) res = Matrix_mul(res,a);
        n >>=1;
        a = Matrix_mul(a,a);
    }
    return (res.v[0][0] + res.v[1][1] * 0) % mod;
}

int main()
{
    int k;
    while(cin >> k)
    {
        Matrix A;
        A.v[0][0] = A.v[0][1] = A.v[1][0] = 1;
        A.v[1][1] = 0;
        ll ans = _pow(A,2 * k + 1);
        ans = (ans - 1 + mod) % mod;
        cout << ans << endl;
    }
    return 0;
}

本次题解如有发现问题的话,麻烦联系计算机214顾芝瑜,谢谢

标签:matrix,int,题解,ll,ans,矩阵,++,res,快速
From: https://www.cnblogs.com/gugu-0369/p/17008310.html

相关文章

  • CodeForces-690#D1 题解
    正文很显然啊,这是在考一个叫连通块的东东,于是蒟蒻的我马上想到了连通块必备:并查集。如果一个块四边连通了其它的块,那么合并这两个块。当然,并查集要用二维的:typedefpai......
  • 【题解】1059: 贴瓷砖
    1059:贴瓷砖题目描述有一块大小是2*n的墙面,现在需要用2种规格的瓷砖铺满,瓷砖规格分别是2*1和2*2,请计算一共有多少种铺设的方法。输入输入的第一行包含一个......
  • 安装算量风管上阀件的规格为该设备所在位置的管道规格怎样快速区分?
    答:通过单类设备的识别软件将同种类型的设备一起计算了,但有可能设备所在管道的规格不一样,那么不同规格的设备是需要区分的,设备计算完成后按管线拆分设备即可。操作步骤如下:定......
  • P6357 题解
    Luogu题面题目描述给定一串长度为\(n\)的数字,数字为\(0\sim9\)之间的任意一个,下标从\(1\)记起。然后进行\(m\)次区间查询,每次查找区间\([l,r]\)的区间和,......
  • JavaWeb项目实战(3)软件快速下载
    前两篇文章里提到的所有文件均可在这里下载:​​https://www.lmonkey.com/tools/java​​......
  • 快速排序
    思路:取一个对比值,然后将他从原数组中取出,跟数组中剩下的值进行对比,需要创建两个数组,一个记录比值小的,一个记录比值大的functionquickSort(arr){if(arr.length<......
  • 【Golang 快速入门】项目实战:即时通信系统
    即时通信系统-服务端项目架构图: 版本迭代:版本一:构建基础Server版本二:用户上线功能版本三:用户消息广播机制版本四:用户业务层封装版本五:在线用户查询版本六:修改用户名......
  • 一个不错的说弱矩阵下的如何沟通的讲座
    最近听了个不错的光环的讲座,说弱矩阵下的沟通管理的,播放地址是:​​https://applyf2jspp3213.h5.xiaoeknow.com/v1/auth?redirect_url=https%3A%2F%2Fapplyf2jspp3213.h5.xi......
  • Windows操作系统TIME_WAIT状态的TCP连接快速回收时间(性能测试时端口不够用)
    https://www.bilibili.com/read/cv16258140大规模Windows环境下,采用Nginx反向代理服务后,操作系统会产生较多TIME_WAIT的TCP(TransmissionControlProtocol)连接,操作系统......
  • Hessian矩阵以及在血管增强中的应用—OpenCV实现
    有别于广为人知的Sobel、Canny等一阶算法,基于Hessian矩阵能够得到图像二阶结果,这将帮助我们深入分析图像本质。Hessian矩阵在图像处理中有着广泛的应用:其中在图像分割......