hdu1757 - A Simple Math Problem

本文详细介绍如何使用矩阵快速幂解决特定类型的数学问题。首先介绍快速幂取模的基本概念及实现方式,然后逐步深入矩阵乘法、矩阵相加等内容,并通过一个具体实例展示了如何构造矩阵来高效求解递推问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大牛牛们说,这是矩阵快速幂,入门的题,

也是很模板的一道题吧

我先慢慢理理,

1.先是快速幂取模(百度文库有一篇超详细的推导 

求得是a^b mod c(是关于数的)

int pow(int a, int b, int c)//也可能需要 long long
{
    int ans = 1;
    a = a % c;
    while(b>0)
    {
       if(b&1)//判断b是否为奇数,或if(b % 2 = = 1)
            ans = (ans * a) % c;
        b = b/2;
        a = (a * a) % c;
    }
    return ans;
}


2.矩阵(x值很大,递推会超时,可以用矩阵加速)

定义一个矩阵的结构体,

struct Matrix  
{  
    int m[Max][Max];  
} 
Matrix a,b;

3.矩阵乘法(O(n^3)
Matrix operator*(Matrix a,Matrix b)    
{    
    int i,j,k;    
    Matrix c;    
    for (i=0;i<len;i++)    
    {    
        for (j=0;j<len;j++)    
        {    
            c.m[i][j] = 0;    
            for(k=0;k<len;k++)    
                c.m[i][j]+=(a.m[i][k]*b.m[k][j])%MOD;    
        }    
    }    
    return c;    
} 
4.矩阵相加,更简单些
Matrix operator+(Matrix a,Matrix b)    
{    
    Matrix c;    
    int i,j;    
    for (i=0;i<len;i++)    
    {    
        for(j=0;j<len;j++)    
            c.m[i][j] = (a.m[i][j]+b.m[i][j])%MOD;    
    }    
    return c;    
} 
5. 用operator 是为了重载运算符,

Matrix operator^(Matrix a,int x)    
 {    
     Matrix p = e,q = a;    
     while (x)    
     {    
         if(x&1)//判断是否为奇数的另一种写法
             p = p*q;//此时*被重载成矩阵的乘法了    
         x>>=1;//即x/=2;   
         q = q*q;//都不用再写取模了,已经写进*里了    
     }    
     return p;    
 } 

6.如果不用重载,而是都写成函数,最后快速幂可以写作调用函数

Matrix Pow(Matrix a,Matrix b,int x){  
    while(x){  
        if(x&1){  
            b = Mul(a,b);  //只将operator*改为函数名Mul,再调用就好,没什么差别
        }  
        a = Mul(a,a);  
        x>>=1;  
    }        
    return b;  
}  
7.在知道了以上内容后,来看这一题

求f(k)%m,k的数据很大,递推会超时

想到构造矩阵会快点,总之构造矩阵很重要,大神们的图




可以看出求f(n)只需求出这个矩阵的n-9次方,再与fi相乘,就是答案
代码如下
#include <iostream>
#include <cstdio>
#include <cstring>
int k,mod;
struct matrix
{
    int m[15][15];
};
matrix x,y;//定义两个要用的矩阵
void Init() //清空初始化
{
    memset(x.m,0,sizeof(x.m));
    for(int i=1; i<10; i++)
    {
        x.m[i][i-1] = 1;
    }
    memset(y.m,0,sizeof(y.m));
    for(int i=0; i<10; i++)
    {
        y.m[i][i] = 1;
    }
}
matrix operator*(matrix a,matrix b)
{
    //也可以改成一个函数,如matrix mul(matrix a,matrix b)后面a*b改为mul(a,b)即可
    matrix c;
    for(int i=0; i<10; i++)
    {
        for(int j=0; j<10; j++)
        {
            c.m[i][j] = 0;
            for(int K=0; K<10; K++)
            {
                c.m[i][j]+=(a.m[i][K]*b.m[K][j])%mod;
            }
            c.m[i][j]%=mod;
        }
    }
    return c;


}
matrix Pow(matrix a,matrix b,int c)
{
    //矩阵快速幂
    while(c)
    {
        if(c&1)
        {
            b = a*b;
        }
        a = a*a;
        c>>=1;
    }
    return b;
}


int main()
{


    while(scanf("%d%d",&k,&mod)!=EOF)
    {
        Init();//初始化为单位矩阵
        for(int i=0; i<10; i++)
            scanf("%d",&x.m[0][i]);//直接存入矩阵的第一行,下面的则是InitI()初始化的单位矩阵
        if(k<10)
        {
            printf("%d\n",k%mod);
        }
        else
        {
            matrix res=Pow(x,y,k-9);//res存的是这个矩阵的k-9次方,下面还需与f1到f9相乘
            int ans = 0;
            for(int i=0; i<10; i++)
            {
                ans+=(res.m[0][i]*(9-i))%mod;
                ans%=mod;


            }
            printf("%d\n",ans);
        }


   } return 0;
}
多做几道题,一定要亲手a掉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值