求通項和斐波那契數列的方法一樣,矩陣快速冪。
這道題麻煩在套了三層。
但其實取模這種操作肯定會出現循環的,可以先本地暴出循環節,1000000007對應的循環節是222222224,222222224對應的循環節是183120。
最外層的結果是對1000000007取模,它的內層對222222224取模,可以得到相等的答案,那么222222224的內層對183120取模,也能得到相等的答案,這樣就是分別對三個模數做矩陣快速冪,內層得到的結果返回給外層作為指數。
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 typedef __int64 LL; 5 struct Matrix 6 { 7 LL Mt[2][2]; 8 void init0(){memset(Mt, 0, sizeof(Mt));} 9 void init1() {init0(), Mt[0][0] = Mt[1][1] = 1;} 10 Matrix(){init0();} 11 Matrix(LL num) {init0();Mt[0][0] = Mt[1][1] = num;} 12 Matrix(LL a, LL b, LL c, LL d){Mt[0][0] = a, Mt[0][1] = b, Mt[1][0] = c, Mt[1][1] = d;} 13 Matrix Mul(const Matrix &b, LL mod) 14 { 15 int i, j, k;Matrix res; 16 for(i = 0; i < 2; ++ i) 17 for(j = 0; j < 2; ++ j) 18 for(k = 0; k < 2; ++ k) 19 res.Mt[i][j] = (res.Mt[i][j] + Mt[i][k] * b.Mt[k][j]) % mod; 20 return res; 21 } 22 Matrix Rep(LL p, LL mod) 23 { 24 Matrix b = *this, res(1); 25 if(p == 0) return res; 26 if(p == 1) return b; 27 while(p > 1) 28 { 29 if(p & 1) res = res.Mul(b, mod); 30 b = b.Mul(b, mod); 31 p >>= 1; 32 } 33 return b.Mul(res, mod); 34 } 35 }; 36 LL Cal(LL n, LL mod) 37 { 38 Matrix mm(3, 1, 1, 0), ori(1, 0, 0, 0); 39 if(!n) return 0; 40 return ori.Mul(mm.Rep(n - 1, mod), mod).Mt[0][0]; 41 } 42 int main() 43 { 44 LL n; 45 while(scanf("%I64d", &n) != EOF) 46 printf("%I64d\n", Cal(Cal(Cal(n, 183120), 222222224), 1000000007)); 47 return 0; 48 }