One day when alpc60 went up stairs, he thought that every time he can step over one or two stairs, if there are n stairs, then how many ways he can reach the top?
The clever ACMers, can you help alpc60 to calculate how many ways he can go up n (1 ≤ n ≤ 1,000,000,000) stairs.
Because the number of the answer will be so large, you must output the number module by 9901.
Input is ended with -1 which is not the stairs number.
1 2 5 -1
1 2 8Hint: The Bruce force method will simply lead to the Time Limit Exceeded error, try some efficient method to solve this problem.
Source: NUDT Programming Contest 2009
题意 : 上楼梯, 每次都可以上1节或2节,求有几种上楼方式,是一个典型的斐波那契数列,某状态可以是从两种情况来的,1,上两节到这儿,2,上1节到这儿,就是f[n] = f[n-1]+f[n-2]
但是因为数会很大所以要用到矩阵,和快速矩阵幂
1 /* 2 快速幂矩阵法 3 dp 动态规划 4 a[n] = a[n-1]+ a[n-2]; 这是一个典型的斐波那契数列 一般斐波那契数列算到20的时候已经很大了所以一般来说要用快速法 5 构造矩阵有 6 a[n-1] = q[n-1]; 为了构造一个矩阵 7 上下两式分析有 [ a[n] ] = [1,1]*[a[n-1]] 8 [ a[n-1] ] = [1,0] [a[n-2]] 9 其中要自定义矩阵的乘法 10 然后递推得 转化成求矩阵幂的问题 11 */ 12 13 #include<cstdio> 14 #include<cmath> 15 #define N 9901 16 using namespace std; 17 struct mtx{ 18 // int n;// 矩阵的阶数 19 int a[2][2]; 20 mtx operator * (const mtx o) const { 21 mtx c; 22 // return c.n = n ; 23 c.a[0][0]= c.a[0][1] = c.a[1][0] = c.a[1][1] = 0;//做乘法前初始化 24 for(int i = 0 ; i < 2 ; i++ ) 25 { 26 for(int j = 0 ; j < 2 ; j++) 27 { 28 for(int k = 0 ; k < 2 ; k++) 29 { 30 c.a[i][j] += ((a[i][k]%N)*(o.a[k][j]%N))%N; 31 c.a[i][j] %= N; 32 } 33 } 34 } 35 return c; 36 } 37 };//定义矩阵乘法 38 /* 如果 递归的写数幂是 39 int f(int a ,int b) 40 { 41 int ret = 1; 42 if (b == 1 ) return a; 43 int t = f(a,b/2) 44 t = t*t; 45 if(b&1) return t*a; 46 return t; 47 } 48 49 但是矩阵的乘法一般不写递归形式,因为递归用栈来存储,会爆内存 50 51 非递归形式写数幂 52 53 int f (int a , int b) 54 { 55 int ret = 1; 56 while(b > 0) 57 { 58 if(b&1) ret *= a; 59 a *= a; 60 b >>= 1; 61 } 62 return ret; 63 } 64 int f(int a ,int b ) 65 { 66 int ret; 67 for( ret = 1 ; b ; b>>=1) 68 { 69 if(b&1) ret*=a; 70 a = a * a; 71 } 72 return ret; 73 } 74 75 int f (int a , int b) 76 { 77 int ret ; 78 for(ret = 1 ; b ; b>>=1 , a = a * a %Mod) 79 if(b&1) ret = ret*a%N;////+=要比加快。。。。。也可以写成ret*=a; ret %=a; 80 return ret; 81 } 82 */ 83 84 mtx f(int b) 85 { 86 mtx t; 87 mtx haha ; 88 haha.a[0][0] = haha.a[0][1] = haha.a[1][0] = 1; 89 haha.a[1][1] = 0; 90 91 t.a[0][1] = t.a[1][0] = 0; 92 t.a[1][1] = t.a[0][0] = 1; 93 mtx ret ; 94 //if(b==1) return t; 95 for(ret = t ; b ; b>>=1) 96 { 97 // printf("%d\n", b); 98 if(b&1) ret = ret * haha ; 99 haha = haha * haha; 100 } 101 return ret; 102 } //快速幂矩阵 103 104 105 int main() 106 { 107 int cnt ; 108 while(~scanf("%d",&cnt)&&cnt!=-1) 109 { 110 mtx ans; 111 ans = f(cnt-1); 112 // printf("%d %d\n%d %d\n", ans.a[0][0], ans.a[0][1], ans.a[1][0], ans.a[1][1]); 113 int sum = (1*ans.a[0][0]+1*ans.a[0][1])%N; 114 printf("%d\n",sum); 115 } 116 return 0 ; 117 }