NYOJ301 递推求值(矩阵快速幂)

来源:互联网 发布:拍拍交友软件聊天 编辑:程序博客网 时间:2024/04/29 08:27

题目:

递推求值

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

给你一个递推公式:

f(x)=a*f(x-2)+b*f(x-1)+c

并给你f(1),f(2)的值,请求出f(n)的值,由于f(n)的值可能过大,求出f(n)对1000007取模后的值。

注意:-1对3取模后等于2

输入
第一行是一个整数T,表示测试数据的组数(T<=10000)
随后每行有六个整数,分别表示f(1),f(2),a,b,c,n的值。
其中0<=f(1),f(2)<100,-100<=a,b,c<=100,1<=n<=100000000 (10^9)
输出
输出f(n)对1000007取模后的值
样例输入
21 1 1 1 0 51 1 -1 -10 -100 3
样例输出
5999896
来源
经典题目
上传者
张云聪


这是一道矩阵快速幂的入门加模板题

矩阵快速幂:

1:思想

矩阵快速幂的思想就是跟数的快速幂一样,假如我们要求2^11,次方,我们可以把 11 写成 1+2+8 ,也就是2^0 + 2^1 + 2^3 。那么把一个O(n)的时间复杂度降到了log(n)

矩阵快速幂的思想和数的快速幂是一模一样的,就是要自己实现矩阵的乘法,然后可以套数的快速幂的模板。


2:难点

矩阵题目的难点在于构造矩阵,一般用于有能够推出递推式的题目,推出递推式之后,发现递推O(n)的复杂度时间比较大,那么我们可以构造一个矩阵,然后用矩阵快速幂降低到log(n)的时间复杂度



代码:

#include <cstdio>#include <cstring>#include <cctype>#include <string>#include <set>#include <iostream>#include <stack>#include <cmath>#include <queue>#include <vector>#include <algorithm>#define mem(a,b) memset(a,b,sizeof(a))#define inf 0x3f3f3f3f#define mod 1000007#define N 3#define M 1000000+10#define ll long longusing namespace std;struct Matrix{    ll mat[N][N];};Matrix unit_matrix={    1,0,0,    0,1,0,    0,0,1};//单位矩阵Matrix mul(Matrix a,Matrix b)//矩阵相乘{    Matrix res;    for(int i=0; i<N; ++i)        for(int j=0; j<N; ++j)        {            res.mat[i][j]=0;            for(int k=0; k<N; ++k)                res.mat[i][j]=(res.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod;        }    return res;}Matrix pow_matrix(Matrix a,ll n)//矩阵快速幂{    Matrix res=unit_matrix;    while(n)    {        if(n&1)            res=mul(res,a);        a=mul(a,a);        n>>=1;    }    return res;}int main(){    ll t,f1,f2,a,b,c,n;    Matrix tmp,arr;    scanf("%lld",&t);    while(t--)    {        scanf("%lld%lld%lld%lld%lld%lld",&f1,&f2,&a,&b,&c,&n);        if(n==1)            printf("%lld\n",(f1+mod)%mod);        else if(n==2)            printf("%lld\n",(f2+mod)%mod);        else        {            mem(arr.mat,0);            mem(tmp.mat,0);            arr.mat[0][0]=f2,arr.mat[0][1]=f1,arr.mat[0][2]=1;//构造初始矩阵            tmp.mat[0][0]=b,tmp.mat[1][0]=a,tmp.mat[2][0]=c;            tmp.mat[0][1]=tmp.mat[2][2]=1;            Matrix p=pow_matrix(tmp,n-2);            p=mul(arr,p);//注意p和arr不要写反了            ll ans=(p.mat[0][0]+mod)%mod;            printf("%lld\n",ans);        }    }    return 0;}

2017/10/10重做代码:

#include<cstdio>#include<cstring>#include<string>#include<set>#include<iostream>#include<stack>#include<queue>#include<vector>#include<algorithm>#define mem(a,b) memset(a,b,sizeof(a))#define inf 0x3f3f3f3f#define mod 1000007#define debug() puts("what the fuck!!!")#define ll long longusing namespace std;const ll N=3;struct Matrix{ll a[N][N];Matrix(){mem(a,0);}void init(){mem(a,0);for(ll i=0; i<N; i++)a[i][i]=1;}};void print(Matrix a){for(ll i=0; i<N; i++){for(ll j=0; j<N; j++)printf("%d ",a.a[i][j]);puts("");}}Matrix mul(Matrix a,Matrix b){Matrix ans;for(ll i=0; i<N; i++)for(ll j=0; j<N; j++)for(ll k=0; k<N; k++){ans.a[i][j]=(ans.a[i][j]%mod+a.a[i][k]*b.a[k][j]%mod)%mod;}return ans;}Matrix mat_pow(Matrix a,ll n){Matrix ans;ans.init();while(n){if(n&1)ans=mul(ans,a);a=mul(a,a);n>>=1;}return ans;}int main(){ll f1,f2,a,b,c,n,t;scanf("%lld",&t);while(t--){scanf("%lld%lld%lld%lld%lld%lld",&f1,&f2,&a,&b,&c,&n);if(n==1)printf("%lld\n",(f1+mod)%mod);else if(n==2)printf("%lld\n",(f2+mod)%mod);else{Matrix A;A.a[0][0]=b,A.a[1][0]=a,A.a[2][0]=c;A.a[0][1]=A.a[2][2]=1;Matrix p=mat_pow(A,n-2);Matrix B;B.a[0][0]=f2,B.a[0][1]=f1;B.a[0][2]=1;Matrix ans=mul(B,p);printf("%lld\n",(ans.a[0][0]+mod)%mod);}}return 0;}



0 0