标签:
题目大意就是求那个式子y=(5+2√6)^(1+2^x)。
考虑(5+2√6)^n和(5-2√6)^n;
分别设为A和B,
自然A*B=1
考虑A+B,发现奇数次幂的根号消掉了,于是是个整数。
由因为A>1,自然B<1所以说A的小数部分就是1-B,所以A的整数部分就是A+B-1。
于是就是求A+B,便能得到结果。
而这个式子跟特征根求解的一次线性递推式的结果很像。
于是考虑x^2+bx+c=0这个特征方程,跟为5+2√6和5-2√6。
得b=-10,c=1。
于是递推式为f(n+2)=10f(n+1)-f(n-2)。
然后本地打表发现,不管模范围内的任何素数,这个序列的循环节都不是很大。
于是考虑直接暴力循环节,不过记忆化下来。
然后就是考虑2^x模循环节的结果即可,这个用快速幂。
复杂度是O(r+logx),其中r为循环节大小。
题解中通过结论 (p^2- p)(p^2-1)为循环节使用矩阵快速幂.
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #include <set> #include <map> #include <queue> #include <string> #define LL long long using namespace std; const int maxM = 47000; int x, m, r[maxM], f[maxM]; void init() { if (r[m] != -1) return; f[0] = 2%m; f[1] = 10%m; for (int i = 2;; ++i) { f[i] = ((10*f[i-1]-f[i-2])%m+m)%m; if (f[i-1] == f[0] && f[i] == f[1]) { r[m] = i-1; break; } } } //快速幂m^n int quickPow(LL x, int n, int mm) { int a = 1; while (n) { a *= n&1 ? x : 1; a %= mm; n >>= 1 ; x *= x; x %= mm; } return a; } void work() { int k, ans; k = quickPow(2, x, r[m]); k = (k+1)%r[m]; f[0] = 2%m; f[1] = 10%m; for (int i = 2; i <= k; ++i) f[i] = ((10*f[i-1]-f[i-2])%m+m)%m; ans = (f[k]-1+m)%m; printf("%d\n", ans); } int main() { //freopen("test.in", "r", stdin); memset(r, -1, sizeof(r)); int T; scanf("%d", &T); for (int times = 0; times < T; ++times) { printf("Case #%d: ", times+1); scanf("%d%d", &x, &m); init(); work(); } return 0; }
ACM学习历程—HDU 5451 Best Solver(Fibonacci数列 && 快速幂)(2015长春网赛1007题)
标签:
原文地址:http://www.cnblogs.com/andyqsmart/p/4822086.html