码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 5451 广义斐波那契数列

时间:2015-09-21 01:19:07      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:

 这道题目可以先转化:

令f(1) = 5+2√6

f(2) = f(1)*(5+2√6)

...

f(n) = f(n-1)*(5+2√6)

f(n) = f(n-1)*(10-(5-2√6)) = 10*f(n-1)-(5-2√6)f(n-1) = 10*f(n-1) - 10/(5+2√6) f(n-1) = 10*f(n-1) - 10/(5+2√6) * (5+2√6)f(n-2)

= 10*f(n-1) - f(n-2)

那么就可以写成矩阵相乘的形式了

(f(n) , f(n-1)) = (f(n-1) , f(n-2)) (10 , 1

                   -1 , 0) 

但这里2^x+1还是很大,这里就用到广义斐波那契数列找循环节的思想

循环节长度 = (mod-1)*(mod+1)

具体证明可以参考这里:   广义斐波那契数列

那么只要求出对模循环节后的长度进行幂运算就行了

但这里f(i)都是带根号的小数 , 这里就选择用近似的整数代替

5+2√6 = 9.89...

f(0) = (5+2√6)^0 = 1

f(1) = (5+2√6)^1 = 5+2√6

/*囧 想了半天我还是不知道为什么f(0)用2代替 , f(1)用10代替就一定保证之后取到的都是上顶*/

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 100010
 4 #define ll long long
 5 int n,q;
 6 ll MOD;
 7 struct Matrix{
 8     int m[2][2];
 9     void init(){m[0][0]=m[1][1]=1;m[0][1]=m[1][0]=0;}
10     Matrix operator*(const Matrix &p) const{
11         Matrix ret;
12         for(int i=0 ; i<2 ; i++)
13             for(int j=0 ; j<2 ; j++){
14                 ret.m[i][j]=0;
15                 for(int k=0 ; k<2 ; k++){
16                     ret.m[i][j] = (ret.m[i][j]+((ll)m[i][k]*p.m[k][j])%MOD)%MOD;
17                 }
18             }
19         return ret;
20     }
21 };
22 
23 int qpow(int b)
24 {
25     ll ret=1 , a=2;
26     while(b){
27         if(b&1) ret = ret*a%MOD;
28         a = a*a%MOD;
29         b>>=1;
30     }
31     return ret;
32 }
33 
34 Matrix qpow(Matrix a , int b)
35 {
36     Matrix ret;
37     ret.init();
38     while(b){
39         if(b&1) ret = ret*a;
40         a = a*a;
41         b>>=1;
42     }
43     return ret;
44 }
45 
46 int main()
47 {
48    // freopen("a.in" , "r" , stdin);
49     int T , cas=0;
50     scanf("%d" , &T);
51     while(T--)
52     {
53         scanf("%d%d" , &n , &q);
54         MOD = (q-1)*(q+1);
55         n = qpow(n);
56         MOD = q;
57         Matrix a;
58         a.m[0][0]=10 , a.m[1][0]=-1 , a.m[0][1]=1 , a.m[1][1]=0;
59         a = qpow(a , n);
60         ll val = (ll)10*a.m[0][0]+(ll)2*a.m[1][0];
61         val = ((val%MOD)+MOD)%MOD;
62         printf("Case #%d: %I64d\n" , ++cas , (val+MOD-1)%MOD);
63     }
64     return 0;
65 }

 

HDU 5451 广义斐波那契数列

标签:

原文地址:http://www.cnblogs.com/CSU3901130321/p/4824910.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!