链接:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1100
碰到递推大数再取模的问题,如果MOD不是特别大的情况下,而且f[i]的值比较连续的情况下可以考虑采用寻找循环节的方法解题,当然为了提高程序的效率,递推的过程可以采用矩阵快速幂(请参考矩阵快速幂II);
寻找循环节的方法如下:
#include <stdio.h>
#define MOD 10007 //宏定义;
int f[20016] = {1,2,4}; //对数组的声明及前三项初始化;
int main()
{
int n, t;
for (int i=3; ; i++) {
f[i] = (f[i-1] + f[i-2] + 1) % MOD; //递推表达式,及每次取模;
/*
if (f[i]==2 && f[i-1]==1) { //寻找循环节;
printf("%d\n", i);
break;
}
*/
}
while(scanf("%d", &t) != EOF) {
while(t--) {
scanf("%d", &n);
printf("%d\n", f[n%20016]); //因为n的范围很大,所以在输出f[n]之前先对n进行循环节取模;
}
}
return 0;
}
矩阵快速幂的递推法:
#include<stdio.h>
#include<math.h>
const int MAX=10007;
int A[1][3];
int B[3][3]={0,1,0,1,1,0,0,1,1};
int C[3][3];
void mul(int a[][3],int b[][3],intc[][3]){//功能,求出a*b存在c里
int i,j,h;
for(i=0;i<3;i++)
for(j=0;j<3;j++){
c[i][j]=0;
for(h=0;h<3;h++)
c[i][j]+=a[i][h]*b[h][j];
c[i][j]%=MAX;
}
}
void qiu(int x,int a[][3]){//求出 B 的x次方,存在a里(二分)
int i,j;
int b[3][3];
if(x==1){//x等于1时,直接把B存在a里
for(i=0;i<3;i++)
for(j=0;j<3;j++)
a[i][j]=B[i][j];
return;
}
if(x%2==0){
qiu(x/2,b);
mul(b,b,a);
}
else{
qiu(x-1,b);
mul(b,B,a);
}
}
int main(){
int c[3][3];
int i,j,h,l,p,n,N;
while(scanf("%d",&N) != EOF)
while(N--){
scanf("%d",&p);
A[0][0]=0;A[0][1]=1;A[0][2]=1;
qiu(p+1,C);//表示求f[n];
mul(A,C,c);
n = c[0][0]%MAX;
printf("%d\n", n);
}
return 0;
}