您的位置:首页 > 编程语言

NYoj_301_递推求值 解题思路和代码

2018-01-22 13:50 351 查看

题目

描述

给你一个递推公式:

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取模后的值

样例输入

2
1 1 1 1 0 5
1 1 -1 -10 -100 3


样例输出

5
999896


要求

时间限制:1000 ms | 内存限制:65535 KB

解决方法

(一)使用递归方法

1、解题思路

拿到这个题目首先想到的是使用最直观的递归方式。

2、程序代码

#include <iostream>
using namespace std;

int remainder(int n){
int temp = n%1000007;
int res = temp > 0 ? temp: (temp+1000007);
return res;
}

int funDiGui(int f1, int f2, int a, int b, int c, int n){
if(n==1){
return remainder(f1);
}
else if(n==2){
return remainder(f2);
}
else{
return remainder(a*funDiGui(f1, f2, a, b, c, n-2) + b*funDiGui(f1, f2, a, b, c, n-1) + c);
}
}

int main()
{
int T; //T表示测试数据的组数
cin >> T;
while(T--){
unsigned int *p = new unsigned int[6];
for (int i = 0; i < 6; ++i){
cin >> p[i];
}
cout << funDiGui(p[0], p[1], p[2], p[3], p[4], p[5]) << endl;
}
return 0;
}


3、运行结果

RunTimeError.

(二)使用递推方法

1、解题思路

使用递归方法时间超时,递推方法好像比递归少消耗时间一点,所有又试了下递推的方式。

2、程序代码

#include <iostream>
using namespace std;

int remainder(int n){
int temp = n%1000007;
int res = temp > 0 ? temp: (temp+1000007);
return res;
}

int funDiTui(int f1, int f2, int a, int b, int c, int n){
int *p = new int
;
p[0] = remainder(f1);
p[1] = remainder(f2);
for ( int j = 2; j < n; ++j){
p[j] = remainder(a*p[j-2] + b*p[j-1] + c);
}
return p[n-1];
}

int main()
{
int T; //T表示测试数据的组数
cin >> T;
while(T--){
unsigned int *p = new unsigned int[6];
for (int i = 0; i < 6; ++i){
cin >> p[i];
}
cout << funDiTui(p[0], p[1], p[2], p[3], p[4], p[5]) << endl;
}
return 0;
}


3、运行结果

MemoryLimitExceeded.

(三)使用矩阵方法

1、解题思路

递归和递推方法在性能上都不符合要求,在网上看了下解题报告,需要使用矩阵来解决,思路分析如下:

f3=a∗f1+b∗f2+c

f4=a∗f2+b∗f3+c

...

通过矩阵表达如下:

令A=b10a00c01,B=f2f11

于是AB=b∗f2+a∗f1+c=f3f21,即第一行的值是f3;

A2B=A∗A∗B=b10a00c01∗f3f21=b∗f3+a∗f2+c=f4f31=…

故fn是An−2B 结果的第一行的值。

注意: 在下面的代码中,B使用的仍然是一个3*3的矩阵,不过只有第一列有意义,后两列都是0,对结果不产生影响。

2、程序代码

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

#define mod 1000007
#define N 3
typedef long long LL;

struct Matrix{
LL mat

;
};

Matrix unit_matrix = {
1, 0, 0,
0, 1, 0,
0, 0, 1
};  //单位矩阵

Matrix mul(Matrix a, Matrix b){  //矩阵相乘
Matrix res;
memset(res.mat, 0, sizeof(res.mat));
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] += a.mat[i][k] * b.mat[k][j];
res.mat[i][j] = (res.mat[i][j] + mod)%mod;  //取模
}
}
return res;
}

Matrix pow_matrix(Matrix a, LL n){  //矩阵快速幂
Matrix res = unit_matrix;
for (; n; n >>= 1){
if(n&1) res = mul(res, a);
a = mul(a, a);
}
return res;
}

int main()
{
Matrix x, y;
LL T, f1, f2, a, b, c, n; //T表示测试数据的组数
cin >> T;
while(T--){
cin >> f1 >> f2 >> a >> b >> c >> n;
memset(x.mat, 0, sizeof(x.mat));
memset(y.mat, 0, sizeof(y.mat));
x.mat[0][0] = b;   //注意,在C++中,数组的下标从0开始,所以要特别注意
x.mat[0][1] = a;
x.mat[0][2] = c;
x.mat[1][0] = 1;
x.mat[1][1] = 0;
x.mat[1][2] = 0;
x.mat[2][0] = 0;
x.mat[2][1] = 0;
x.mat[2][2] = 1;
y.mat[0][0] = f2;
y.mat[1][0] = f1;
y.mat[2][0] = 1;
if (n == 1){
cout << (f1+mod)%mod << endl;
}
else if ( n == 2){
cout << (f2+mod)%mod << endl;
}
else{
x = pow_matrix(x, n-2);
x = mul(x, y);
cout << (x.mat[0][0] + mod)%mod << endl;
}
}
return 0;
}


3、运行结果

运行通过,时间:355,内存:8648
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: