1126 求递推序列的第N项
基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题
有一个序列是这样定义的:f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.
给出A,B和N,求f(n)的值。
Input
输入3个数:A,B,N。数字之间用空格分割。(-10000 <= A, B <= 10000, 1 <= N <= 10^9)
Output
输出f(n)的值。
Input示例
3 -1 5
Output示例
6
思路:
1.设X矩阵为 X = ,Y=
,可得X*Y=
,归纳可得X^(n-2) * Y =
。其中X^(n-2)可由矩阵快速幂运算,由于Y中f(2)=1,f(1)=1,我们不必再去乘Y矩阵,输出时直接输出(X[0][0]+X[0][1])%7,相当于乘以Y矩阵。把矩阵快速幂运算模板改一下就好了。
2.由于是mod7的关系,只有0,1,2,3,4,5,6这7种状态,且f(1)=f(2)=1,所以f(n)的值是循环分布的。只要当f(i-1)=f(i)=1出现时就有了循环节,和f(1)=f(2)=1一样。找出循环节的长度也就是找出了规律。可见循环节最长为7*7=49.因为,一个f()的状态有7种,连续的二个f()组合就是7*7=49,此时会出现f(i-1)=f(i)=1。
思路1:
//矩阵幂运算
#include<stdio.h>
#include<string.h>
using namespace std;
#define data 7
struct mat{
long long a[2][2];
};
mat mat_return(mat x,mat y){
mat res;
memset(res.a ,0,sizeof(res.a));
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
{
res.a[i][j]=(res.a[i][j]+x.a[i][k]*y.a[k][j]%data)%data;
}
return res;
}
int main()
{
long long n,A,B;
scanf("%lld%lld%lld",&A,&B,&n);
n-=2;
mat c,res;
c.a[0][0]=A,c.a[0][1]=B,c.a[1][0]=1,c.a[1][1]=0;//构造的矩阵
memset(res.a,0,sizeof(res.a));
for(int i=0;i<2;i++)
res.a[i][i]=1;//单位矩阵 ,都一样
while(n>0){//接下来就类似快速幂运算了
if(n&1)
res=mat_return(res,c);
c=mat_return(c,c);
n/=2;
}
printf("%lld\n",(res.a[0][1]+res.a[0][0]+7)%7);
return 0;
}
思路2:
#include<stdio.h>
#include<string.h>
using namespace std;
#define mod 7
#define ll long long
ll f[50];
int main()
{
ll a,b,n,i;
scanf("%lld%lld%lld",&a,&b,&n);
f[1]=f[2]=1;
for(i=3;i<50;i++) {
f[i]=((a*f[i-1]+b*f[i-2])%mod+mod)%mod;
if(f[i-1]==1&&f[i]==1)
{
break;
}
}
i-=2;f[0]=f[i];
printf("%lld %lld\n",f[n%i],i);
return 0;
}