【矩阵快速幂】 hdu5667 Sequence 、nyoj1000 又见斐波那契数列

Sequence

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1999    Accepted Submission(s): 653


Problem Description
     Holion August will eat every thing he has found.

     Now there are many foods,but he does not want to eat all of them at once,so he find a sequence.

fn=1,ab,abfcn1fn2,n=1n=2otherwise

     He gives you 5 numbers n,a,b,c,p,and he will eat  fn  foods.But there are only p foods,so you should tell him  fn  mod p.
 

Input
     The first line has a number,T,means testcase.

     Each testcase has 5 numbers,including n,a,b,c,p in a line.

    1T10,1n1018,1a,b,c109 , p  is a prime number,and  p109+7 .
 

Output
     Output one number for each case,which is  fn  mod p.
 

Sample Input
  
  
1 5 3 3 3 233
 

Sample Output
  
  
190
 

Source
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:   6022  6021  6020  6019  6018 
 
这两道题都是以固定常数为底,对指数进行矩阵快速幂,应该多列几个展开式就可以看出规律了;
因为指数,还要用费马小定理,在矩阵相乘的代码中有相应的操作,即取余(mod-1)。


代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;
typedef pair<int,int > P;
typedef long long LL;
const int maxn=100;
#define N 3
//#define mod 1000007

LL n,a,b,c,p;
struct Matrix
{
    LL mat[N][N];
    Matrix()
    {
        memset(mat,0,sizeof(mat));
    }
};

Matrix mul(Matrix a,Matrix b)
{
    Matrix res;
    for(int i=0; i<N; i++)
        for(int j=0; j<N; j++)
        {
            for(int k=0; k<N; k++)
            {
                res.mat[i][j]+=(a.mat[i][k]*b.mat[k][j])%(p-1);
                res.mat[i][j]%=(p-1);
            }
        }
    return res;
}

Matrix pow_matrix(Matrix a,LL n)//矩阵快速幂;
{
    Matrix res;
    for(int i=0; i<N; i++) //初始化为单位矩阵;
        res.mat[i][i]=1;
    while(n!=0)
    {
        if(n&1)
            res=mul(res,a);
        a=mul(a,a);
        n>>=1;
    }
    return res;
}

LL f(LL a,LL b)
{
    if(a%p==0)
        return 0;
    a%=p;

    LL t,y;
    t=1;
    y=a;
    while(b!=0)
    {
        if(b&1==1)
        {
            t=t*y%p;
        }
        y=y*y%p;
        b=b>>1;
    }
    return t;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        LL ans=0;
        scanf("%lld%lld%lld%lld%lld",&n,&a,&b,&c,&p);
        LL f1=0,f2=b;

        if(n==1)  printf("1\n");
        else  if(n==2)  printf("%lld\n",f(a,b)%p);
        else
        {
            Matrix A,B;
            A.mat[0][0]=f2;  //构造矩阵!!
            A.mat[1][0]=f1;
            A.mat[2][0]=b;
            B.mat[0][0]=c;
            B.mat[0][1]=1;
            B.mat[0][2]=1;
            B.mat[1][0]=1;
            B.mat[2][2]=1;

            B=pow_matrix(B,n-2);
            A=mul(B,A);

//            ans=(A.mat[0][0])%p;
//            ans=f(a,ans,p);
            ans=f(a,A.mat[0][0]);

            printf("%lld\n",ans%p);
        }
    }
    return 0;
}


又见斐波那契数列

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 4
描述

斐波那契数列大家应该很熟悉了吧。下面给大家引入一种新的斐波那契数列:M斐波那契数列。 M斐波那契数列F[n]是一种整数数列,它的定义如下:

F[0] = a
F[1] = b
F[n] = F[n-1] * F[n-2] ( n > 1 )

现在给出a, b, n聪明的你能求出F[n]的值吗?

输入
输入包含多组测试数据;
每组数据占一行,包含3个整数a, b, n( 0 <= a, b, n <= 10^9 )
输出
对每组测试数据请输出一个整数F[n],由于F[n]可能很大,你只需输出F[n]对1000000007取模后的值即可,每组数据输出一行。
样例输入
0 1 0 
6 10 2
样例输出
0 
60
上传者
TC_李远航

这道题和上道题是同类型的,都是指数参与矩阵操作,但这道题有两个底;所以我们构造矩阵的时候需要注意一下,有两个指数的变换;
因为指数,还要用费马小定理,在矩阵相乘的代码中有相应的操作,即取余(mod-1)。


代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;
typedef pair<int,int > P;
typedef long long LL;
const int maxn=100;
#define N 4
#define mod 1000000007

struct Matrix
{
    LL mat[N][N];
    Matrix()
    {
        memset(mat,0,sizeof(mat));
    }
};

Matrix mul(Matrix a,Matrix b)
{
    Matrix res;
    for(int i=0; i<N; i++)
        for(int j=0; j<N; j++)
        {
            for(int k=0; k<N; k++)
            {
                res.mat[i][j]+=a.mat[i][k]*b.mat[k][j]%(mod-1);
                res.mat[i][j]%=(mod-1);
            }
        }
    return res;
}

Matrix pow_matrix(Matrix a,LL n)//矩阵快速幂;
{
    Matrix res;
    for(int i=0; i<N; i++) //初始化为单位矩阵;
        res.mat[i][i]=1;
    while(n!=0)
    {
        if(n&1)
            res=mul(res,a);
        a=mul(a,a);
        n>>=1;
    }
    return res;
}

LL f(LL a,LL b)
{
    LL t,y;
    t=1;
    y=a;
    while(b!=0)
    {
        if(b&1==1)
        {
            t=t*y%mod;
        }
        y=y*y%mod;
        b=b>>1;
    }
    return t;
}

int main()
{
    LL a,b,n;
    while(~scanf("%lld%lld%lld",&a,&b,&n))
    {
        if(n==0)  printf("%lld\n",a%mod);
        else if(n==1)  printf("%lld\n",b%mod);
        else
        {
            LL f2=0,f1=1,g2=1,g1=0;

            Matrix A,B;
            A.mat[0][0]=f2;  //构造矩阵!!
            A.mat[1][0]=f1;
            A.mat[2][0]=g2;
            A.mat[3][0]=g1;

            B.mat[0][0]=1;
            B.mat[0][1]=1;
            B.mat[1][0]=1;
            B.mat[2][2]=1;
            B.mat[2][3]=1;
            B.mat[3][2]=1;

            B=pow_matrix(B,n-1);
            A=mul(B,A);

            LL ans1=f(a,A.mat[0][0]);
            LL ans2=f(b,A.mat[2][0]);
            printf("%lld\n",ans1*ans2%mod);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值