题意:
给你一个数列 ,其中
,
,
求 的值。
解法一(暴力递推,不可AC):
根据
可得出
,因此我们直接循环递推过去即可。
这边我们采用滚动数组的形式,由于每一个
只依赖连续的两个值求解,故我们开一个长度为
的数组,接下来我们来模拟『填写』
值的过程
为了方便,我们将
映射到
,如
表示原来的
,
表示原来的
class Solution {
public:
const int mod=1e9+7;
int f[2];//采用滚动数组
int solve(int a, int b, int n) {
f[0]=a;
f[1]=b;
for(int i=2;i<n;i++){
f[i%2]=(f[(i-1)%2]-f[(i-2)%2]+mod)%mod;
}
return f[(n+1)%2];//这边我们把f[1~n]对应到f[0~n-1],故我们是求f[n-1],采用滚动数组即f[(n-1+2)%2]=f[(n+1)%2]
}
}; 时间复杂度: ,我们需要一次循环依次递推过去,故时间复杂度为
空间复杂度: ,我们需要开一个长度为2的滚动数组,故空间复杂度为
解法二(正解,矩阵快速幂):
由 ,我们可以构造如下矩阵乘法式子:
又可得:
代码:
const int mod=1e9+7;
class Solution {
public:
struct mat{
int A[2][2];
inline mat operator * (const mat& other)const{//矩阵乘法
mat ret;
memset(ret.A,0,sizeof ret.A);
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
ret.A[i][j]+=1ll*A[i][k]*other.A[k][j]%mod;//注意爆int
ret.A[i][j]%=mod;//A[i][j]=(A[i][j]+X)%mod
}
}
}
return ret;
}
};
mat ksm(mat a,int b){//矩阵快速幂
mat ret;
memset(ret.A,0,sizeof ret.A);
for(int i=0;i<2;i++)ret.A[i][i]=1;//单位矩阵
while(b){
if(b&1){
ret=ret*a;
}
a=a*a;
b>>=1;
}
return ret;
}
int solve(int a, int b, int n) {
if(n==1)return a;
if(n==2)return b;//特殊判断
a=(a+mod)%mod;//把负数弄成正数
b=(b+mod)%mod;
mat r;
r.A[0][0]=1,r.A[0][1]=(-1+mod)%mod;//取模意义下弄成正数
r.A[1][0]=1,r.A[1][1]=0;
r=ksm(r,n-2);
int ans=(1ll*r.A[0][0]*b%mod+1ll*r.A[0][1]*a%mod)%mod;//A[0][0]*f(2)+A[0][1]*f(1)
//模拟矩阵乘法求出f[n]
return ans;
}
}; 时间复杂度: ,矩阵的大小为
,故矩阵乘法的时间复杂度可视为常数,矩阵快速幂需要进行
次乘法运算,故时间复杂度为
空间复杂度: ,仅需保存
级别内存的矩阵即可。

京公网安备 11010502036488号