数列----快速幂

 题目信息如图所示:

 刚开始思考,以为难点是在大数相乘,写了一个字符串传参的大数函数(模拟简单的乘法),但是发现没法取模,以及循环次数太多了,k的值太大。请教了同学,得知使用矩阵快速幂来解题。

矩阵快速幂就是利用a^b次幂,b写成2进制时,比如,m=2^11,对应的11的2进制位1011,那么从2^1,2^2,2^4,2^8每个数都是前面一个数的平方xi(前面的数自己乘自己),那么,从1011的末尾开始,为1的话,就取过来,做m=m*xi,这样子就可减少乘的次数。时间复杂度变为O(log2N)。矩阵相乘也是类似的想法。

\small \begin{bmatrix} a_{i} &a_{i-1} \end{bmatrix} = \begin{bmatrix} a_{i-1} &a_{i-2} \end{bmatrix} \begin{bmatrix} v &1 \\ u & 0 \end{bmatrix}

\small \begin{bmatrix} a_{i} &a_{i-1} \end{bmatrix} = \begin{bmatrix} a_{2} &a_{1} \end{bmatrix} \begin{bmatrix} v &1 \\ u & 0 \end{bmatrix}^{i-2}

 ,ai=(ai-1)*v+(ai-2)*u,最后得出,v,u,1,0组成的二次矩阵的i-2次幂(记为A),即有ai=a2*A[0][0]+a1*A[1][0]。

根据给出的递推公式,转为矩阵的幂进行计算是关键。

#include<iostream>
#include<cstring>
using namespace std;

//构建一个2*2的矩阵
const int mod=1000000007;
struct Mtx
{
    long long a[2][2];//用于存储二维的数据
    void init()
    {
        memset(a,0,sizeof(a));
        for(int i=0; i<2; i++) //单位矩阵
            a[i][i]=1;
    }
};



//定义矩阵相乘函数

Mtx mul(Mtx m1,Mtx m2)
{

    Mtx m3;
    memset(m3.a,0,sizeof(m3));
    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++)
            for(int k=0; k<2; k++)
            {
                m3.a[i][j]+=m1.a[i][k]*m2.a[k][j];
                m3.a[i][j]%=mod;
            }
    return m3;
}
//测试矩阵结果
void output(Mtx m)
{
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
            cout<<m.a[i][j]<<" ";
        cout<<endl;
    }

}
//矩阵快速幂
Mtx pow(Mtx m1,int n)
{
    Mtx ans,res;
    ans.init();
    res = m1;
    while(n)
    {
        if(n&1==1)
        {
            ans = mul(ans,res);
        }
        res = mul(res,res);
       // output(res);
        n>>=1;//去掉该数的二进制最后一位
    }
    return ans;
}

int main()
{

    int x,u,v;
    long long k;
    cin>>x>>u>>v>>k;
    //x=1,u=2,v=3,k=4;
    Mtx m1;
    Mtx m2;

    m1.init();
    m1.a[0][0]=v;
    m1.a[0][1]=1;
    m1.a[1][0]=u;
    m1.a[1][1]=0;
    //m2 = mul(m1,m1);

    // output(m2);
    m2 = pow(m1,k-2);
    output(m2);
    cout<<(x*x*m2.a[0][0]+x*m2.a[1][0])%mod;
    return 0;
}

更新。。。。。。

返回结果还有一组数据是TLE。。。

原来是结构体太慢,然后试着用数组代替结构体,ac。

代码如下。。(不会传参)用全局的数组。。决定该学习下传参了。。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

//构建一个2*2的矩阵
const __int64 mod=1000000007;

__int64 m3[2][2];
__int64 b[2][2];
//定义矩阵相乘函数

void mul(__int64 m1[][2],__int64 m2[][2])
{
    m3[0][0]=0;
    m3[0][1]=0;
    m3[1][0]=0;
    m3[1][1]=0;

    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++)
            for(int k=0; k<2; k++)
            {
                m3[i][j]+=m1[i][k]*m2[k][j];

                m3[i][j]%=mod;
            }

}
//测试矩阵结果

//矩阵快速幂
void pow(__int64 a[][2],__int64 n)
{

    //b[2][2]={1,0,0,1};
    b[0][0]=1;
    b[0][1]=0;
    b[1][0]=0;
    b[1][1]=1;
    while(n)
    {
        if(n&1)
        {
            mul(a,b);
            b[0][0]=m3[0][0];
            b[0][1]=m3[0][1];
            b[1][0]=m3[1][0];
            b[1][1]=m3[1][1];
        }
        mul(a,a);
        a[0][0]=m3[0][0];
        a[0][1]=m3[0][1];
        a[1][0]=m3[1][0];
        a[1][1]=m3[1][1];
        // output(res);
        n>>=1;//去掉该数的二进制最后一位
    }

}

int main()
{

    int x,u,v;
    __int64 k;
    cin>>x>>u>>v;
    scanf("%I64d",&k);
    //x=1,u=2,v=3,k=4;
    __int64 a[2][2];


    a[0][0]=v;
    a[0][1]=1;
    a[1][0]=u;
    a[1][1]=0;
    //m2 = mul(m1,m1);

    if(k==1)
    {
        printf("%I64d",(__int64)x);
    }
    else if(k==2)
    {
        printf("%I64d",(__int64)x*x);
    }
    else
    {

        pow(a,k-2);
//        cout<<b[0][0]<<"===>"<<b[0][1]<<endl;
//        cout<<b[1][0]<<"===>"<<b[1][1]<<endl;

          printf("%I64d",(__int64)(x*x*b[0][0]+x*b[1][0])%mod);
    }

    return 0;
}



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值