hdu5950 Recursive sequence(矩阵快速幂:模板类题目,矩阵快速幂的扩展与学习,复习必看题目)

关于矩阵快速幂构造矩阵的学习,推荐一篇非常完美的博客:http://blog.csdn.net/u012061345/article/details/52224623(居家旅行必备!!!!超强)

题目链接:

http://acm.split.hdu.edu.cn/showproblem.php?pid=5950

题目大意:

给你一个递推公式,然后让你求解第n项的结果。

题目思路:

给你递推式,那么这就是一个很裸的矩阵快速幂的题目。那么解题的关键就是求解相应的系数矩阵了。

已知递推公式:F(n) = 2*F(n-2) + F(n-1) + nF(1) = aF(2) = b;给定一个N,求F(N)等于多少?


不知道的点:

一开始用的以前写的模板,狂wa不止,改了板子才写对了。不知所以。


狂wa的代码:

#include <bits/stdc++.h>  

using namespace std;  
typedef long long ll; 

const ll mod = 2147493647;  //这个地方是 ll 而不是 int 
const int Size = 7;  //size的大小按照题目的最大数据大小给  
  
struct Matrix  
{  
    ll m[Size][Size];  
};  
  
Matrix Mul(Matrix a,Matrix b) //矩阵的乘法  
{  
    Matrix c;  
    memset(c.m,0,sizeof(c.m));  
    for(int i=0;i<Size;i++)  
        for(int j=0;j<Size;j++)  
        for(int k=0;k<Size;k++)  
        c.m[i][j] = ((a.m[i][k]*b.m[k][j])%mod+c.m[i][j])%mod;  
  
    return c;  
}  
  
Matrix quick(Matrix a,ll n) //二分的快速幂处理  
{  
    Matrix res;  
    memset(res.m,0,sizeof(res.m));  
    for(int i=0;i<Size;i++)  
        res.m[i][i]=1;  
  
    while(n){  
        if(n&1) res = Mul(res,a);  
        n>>=1;  
        a = Mul(a,a);  
    }  
    return res;  
}  
  
int main()  
{  
    Matrix p;
    memset(p.m,0,sizeof(p.m));
    p.m[0][1] = 1;
    p.m[1][1] = p.m[1][2] = p.m[1][6] = 1;
    p.m[2][2] = p.m[2][6] = 1;
    p.m[1][0] = 2; p.m[1][3] = p.m[1][5] = p.m[2][3] = p.m[2][5] = 4;
    p.m[1][4] = p.m[2][4] = 6;
    p.m[3][3] = p.m[4][4] = p.m[5][5] = p.m[6][6] = 1;
    p.m[3][6] = p.m[4][6] = p.m[5][6] = 1;
    p.m[3][4] = p.m[3][5] = 3;
    p.m[4][5] = 2;
    int t;
    ll n,a,b;
    scanf("%d",&t);
        while(t--){
            scanf("%I64d %I64d %I64d",&n,&a,&b);
            if(n==1) printf("%I64d\n",a);
            else if(n==2) printf("%I64d\n",b);
            else{ 
            Matrix ans = quick(p,n-2);
            ll ANS = 0;
            ANS = (ANS+ans.m[1][0]*a)%mod;
            ANS = (ANS+ans.m[1][1]*b)%mod;
            ANS = (ANS+ans.m[1][2]*16)%mod;
            ANS = (ANS+ans.m[1][3]*8)%mod;
            ANS = (ANS+ans.m[1][4]*4)%mod;
            ANS = (ANS+ans.m[1][5]*2)%mod;
            ANS = (ANS+ans.m[1][6]*1)%mod;
            
            printf("%I64\n",ANS);
            }
        }
        return 0;
}  


ac代码:

#include <bits/stdc++.h>

using namespace std;

#define ll long long 
const ll mod = 2147493647;
const int size = 7;

//定义矩阵乘法 
struct matrix{
    ll arr[size][size];
    matrix operator*(matrix b){ //乘法重载 
        matrix ans;
        ll tmp;
        for(int i=0; i<size; i++)
            for(int j=0; j<size; j++){
                ans.arr[i][j] = 0;
                for(int k=0; k<size; k++){
                    tmp = (arr[i][k]*b.arr[k][j])%mod;
                    ans.arr[i][j] = (ans.arr[i][j] + tmp)%mod;
                }        
            }
        return ans;
    }
};

//矩阵快速幂 
matrix quick_pow(matrix a,ll N){
    matrix ans;
    memset(ans.arr,0,sizeof(ans.arr));
    for(int i=0; i<size; i++)
        ans.arr[i][i] = 1;
    while(N){
        if(N&1)
            ans = ans*a;
        a = a*a;
        N /= 2;; 
    }
    return ans;
}

int main(){
    
    matrix a;
    memset(a.arr,0,sizeof(a.arr));
    a.arr[0][1] = 1;
    a.arr[1][1] = a.arr[1][2] = a.arr[1][6] = 1;
    a.arr[2][2] = a.arr[2][6] = 1;
    a.arr[1][0] = 2; a.arr[1][3] = a.arr[1][5] = a.arr[2][3] = a.arr[2][5] = 4;
    a.arr[1][4] = a.arr[2][4] = 6;
    a.arr[3][3] = a.arr[4][4] = a.arr[5][5] = a.arr[6][6] = 1;
    a.arr[3][6] = a.arr[4][6] = a.arr[5][6] = 1;
    a.arr[3][4] = a.arr[3][5] = 3;
    a.arr[4][5] = 2;
    int T;
    scanf("%d",&T);
    ll N,aa,bb;
    while(T--){
        scanf("%I64d %I64d %I64d",&N,&aa,&bb);
        if(N==1)
            printf("%I64d\n",aa);
        else if(N==2)
            printf("%I64d\n",bb);
        else{
            matrix ans = quick_pow(a,N-2);
            ll ANS = 0;
            ANS = (ANS+ans.arr[1][0]*aa)%mod;
            ANS = (ANS+ans.arr[1][1]*bb)%mod;
            ANS = (ANS+ans.arr[1][2]*16)%mod;
            ANS = (ANS+ans.arr[1][3]*8)%mod;
            ANS = (ANS+ans.arr[1][4]*4)%mod;
            ANS = (ANS+ans.arr[1][5]*2)%mod;
            ANS = (ANS+ans.arr[1][6]*1)%mod;
            printf("%I64d\n",ANS);
        }
    } 
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值