[集训笔记1st](hdu-4151 Best Solver) (共轭构造/广义斐波那契数列递推/找循环节/快速幂/矩阵快速幂)
试着向教主学习看能不能写个博客记笔记。。
说不定就咕咕咕了…
题意
求 ⌊(5+26)1+2x⌋%M\lfloor\left(\\5+2\sqrt6\right)^{1+2^{x}}\rfloor\%M⌊(5+26)1+2x⌋%M, x∈[0,232)x\in\left[\\0,2^{32}\right)x∈[0,232), M≤46637M \leq46637M≤46637
从一个刚会矩阵快速幂的萌新视角看这道题:
难点1:无理数不能在快速幂中求模运算
难点2:指数好大啊。。
难点1的解决办法:
求⌊(a+b)n⌋%M\lfloor\left(\\a+\sqrt{b}\right)^{n}\rfloor\%M⌊(a+b)n⌋%M 或者 ⌈(a+b)n⌉%M\lceil\left(\\a+\sqrt{b}\right)^{n}\rceil\%M⌈(a+b)n⌉%M的通用解决办法。(a−ba - ba−b等于1的可以这样做)
转化为广义斐波那契数列广义斐波那契数列的定义:Fib(x)=p∗Fib(x−1)+q∗Fib(x−2)Fib(x)=p * Fib(x-1) + q * Fib(x - 2)Fib(x)=p∗Fib(x−1)+q∗Fib(x−2)
广义斐波那契数列的常数矩阵:
[pq10]\left[\begin{matrix}p& q \\1 & 0\end{matrix} \right][p1q0]
与FibonocciFibonocciFibonocci数列类比:Fibonacci(n)=15[(1+52)n−(1−52)n]Fibonacci(n) = \frac1{\sqrt5}\left[\left(\frac{1+\sqrt5}{2}\right)^{n}-\left(\frac{1-\sqrt5}{2}\right)^{n}\right]Fibonacci(n)=51[(21+5)n−(21−5)n]
那是不是我们要求的这个F(n)F(n)F(n)也可以转化为类似的通项公式呢?
比如说:
F(n)=[(5+26)n+(5−26)n]F(n)=\left[\left(5+2\sqrt6\right)^{n}+\left(5-2\sqrt6\right)^{n}\right]F(n)=[(5+26)n+(5−26)n]
常数的改变只是因为ppp与qqq的不一样而改变了而已。
然后我们设A=(5+26)n,B=(5−26)nA =\left(5+2\sqrt6\right)^{n}, B=\left(5-2\sqrt6\right)^{n}A=(5+26)n,B=(5−26)n
考虑A+BA+BA+B一定是个整数,因为奇数次幂的无理根式相互抵消掉了。
其次因为5−265-2\sqrt65−26是个小于1的正小数,所以BBB也一定小于1,于是不难想到AAA的整数部分与BBB的整数部分一定是和为1的,那么AAA的小数部分就是1−B1-B1−B,(5+26)n\left(5+2\sqrt6\right)^{n}(5+26)n的整数部分就是A+B−1A+B-1A+B−1。
所以这个题的答案就转变为了求广义斐波那契数列Fn%MFn\%MFn%M 的值
我们说过FnFnFn是一个广义斐波那契数列,那么要用矩阵快速幂计算的话就一定要求递推公式,这个不难求:
F(3)=p∗F(2)+q∗F(1)F(3) = p * F(2)+q*F(1)F(3)=p∗F(2)+q∗F(1)
F(2)=p∗F(1)+q∗F(0)F(2) = p * F(1)+q*F(0)F(2)=p∗F(1)+q∗F(0)
解二元一次方程即可得到F(n)=10∗F(n−1)−F(n−2)F(n) = 10*F(n-1) - F(n-2)F(n)=10∗F(n−1)−F(n−2)
我们再来解决指数过大的问题
(emmm感觉费马小定理降幂的条件不一定满足,所以我没有用。。。)
引入新的知识:
循环节广义FibonacciFibonacciFibonacci数列的第nnn项对MMM取模的值总是等于第n%(M−1)∗(M+1))n \%\left(M-1\right)*\left(M+1)\right)n%(M−1)∗(M+1))
对M取模的值,其中(M−1)∗(M+1))\left(M-1\right)*\left(M+1)\right)(M−1)∗(M+1))就是MMM意义下fib数列的一个循环节(不一定是最小的,是最小循环节的整数倍。
思路是打表,等到F[k]=F[2]&&F[k−1]=F[1]F[k]=F[2]\&\&F[k-1]=F[1]F[k]=F[2]&&F[k−1]=F[1]时,k−2k - 2k−2就是MMM意义下最小的循环节。
这样是不是就解决指数过大的问题了,在对2x2^{x}2x求快速幂时,对循环节取模,然后再矩阵快速幂,就可以得到答案啦。
AC代码(递推)
#include<cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; ll MOD, x; ll m; int f[500000], r[500000]; ll quick_pow(ll x, ll a) { ll res = x, ans = 1; do { ans = (a & 1) ? ((ans %= MOD) * (res %= MOD)) % MOD : ans; res *= (res %= MOD); } while (a >>= 1); return ans % MOD; } 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; } } } int main() { int t; scanf("%d", &t); memset(r, -1, sizeof(r)); for (int i = 1; i <= t; i++) { scanf("%lld%lld", &x, &m); init(); MOD = r[m]; ll k; k = (quick_pow(2, x) + 1) % MOD; 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; ll ans = (f[k] - 1 + m) % m; printf("Case #%d: %lld\n", i, ans); } return 0; }
AC代码2(矩阵快速幂)
嫖一手大佬舍友的代码
#include<iostream> #include<cstring> #include<stdio.h> using namespace std; typedef long long ll; const int maxn = 2; ll n; struct mat { ll mp[maxn][maxn]; }; mat mul(mat a, mat b, int mod) { mat temp; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { temp.mp[i][j] = 0; for (int k = 0; k < 2; k++) { temp.mp[i][j] += (a.mp[i][k] * b.mp[k][j] % mod + mod) % mod; } } } return temp; } mat quick(ll b, ll mod) { mat a = {10, -1, 1, 0}; mat ans = {98, 0, 10, 0}; while (b) { if (b & 1) ans = mul(a, ans, mod); a = mul(a, a, mod); b >>= 1; } return ans; } ll quick2(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans = (ans % n * a % n) % n; a = a * a % n; b >>= 1; } return ans % n; } int main() { int n0; cin >> n0; int count = 1; while (n0--) { ll a, mod, m; cin >> a >> mod; n = ((mod - 1) * (mod + 1)); m = quick2(2, a); mat temp = quick(m, mod); ll result = (temp.mp[1][0] - 1) % mod; printf("Case #%d: %d", count++, result); cout << endl; } }
这个题如果掌握了知识点的话,就是一道考验背模板能力的题。
但是因为不会知识点被学长用来提高AK难度了嘤嘤嘤。
感谢lgz学长教我的打表思路,用递推拿了一血。
感谢wjy学姐教我的循环节公式,这样就可以用矩阵快速幂做出来了。
做出来一道网络赛题目,蒟蒻有点小激动。
- hdu 5451 Best Solver -广义斐波那契+矩阵快速幂+共轭构造+循环节
- hdu 5451 Best Solver 快速矩阵乘法 Fibonacci数列的循环节
- HDU 4794 斐波那契数列循环节
- Hdu 5451 Best Solver(快速幂取模+循环节) -2015 ACM-ICPC沈阳网赛1002
- HDU 3977 Evil teacher(斐波那契数列循环节)
- HDU 4794 Arnold 斐波那契数列循环节
- 特征根法求通项+广义Fibonacci数列找循环节 - HDU 5451 Best Solver
- HDU 2814 斐波那契数列的循环节问题
- hdu 5451 Best Solver (特征方程求通项+广义Fibonacci数列找循环节)
- 特征根法求通项+广义Fibonacci数列找循环节 - HDU 5451 Best Solver
- HDU 5451 Best Solver(矩阵快速幂+ 共轭复数 + 循环节 数论啊 )
- 机器学习笔记—再谈广义线性模型
- HDU 3746 Cyclic Nacklace(KMP+最小循环节)
- QDEZ集训笔记【更新中】
- HDU 4291 A Short problem(矩阵快速幂+循环节)
- HDU 1005 循环节(找规律题目)
- HDU--IMNU集训三:人见人爱A-B 快排回顾 以及 bsearch()用法
- HDU 1005 Number Sequence (找循环节)
- hdu 3307 简单的指数循环节
- hdu 5895 Mathematician QSC(快速幂+指数循环节)