寻找循环节

链接: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;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值