hdu 4565 So Easy!(矩陣快速冪)
阿新 • • 發佈:2019-02-09
題目大意:計算題目中所給式子的值。
解題思路:矩陣快速冪。
An = (a+√b)^n, Bn = (a-√b)^n, Cn = An + Bn = (a+√b)^n+(a-√b)^n;
因為說An和Bn共軛,展開式可以互相抵消,所以保證說Cn一定是整數。
(a-1)^2 < b < a^2
-> a-1 < √b < a
-> 0 < a - √b < 1
-> 0 < (a - √b) < 1
-> [ Bn ] = 1
所以有Cn = [ An ]
Sn = Cn % m.
Sn * 2a = Sn * ((a + √b) + (a - √b)) = ((a + √b)^n + (a - √b)^n)*((a + √b) + (a - √b))
= ((a + √b)^(n+1) + (a - √b)^(n+1)) + (a^2-b)((a + √b)^(n-1) + (a - √b)^(n-1))
= Sn+1 + (a^2-b)Sn-1
Sn+1 = 2aSn + (b-a^2)Sn-1.
#include <stdio.h> #include <string.h> #include <math.h> #define MOD(a,b) (((a%b)+b)%b) typedef long long ll; const int N = 2; int m; struct mat { ll s[N][N]; mat () { memset(s, 0, sizeof(s)); } void set (ll a, ll b, ll c, ll d) { s[0][0] = a; s[0][1] = b; s[1][0] = c; s[1][1] = d; } mat operator * (const mat& c) { mat ans; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { for (int k = 0; k < N; k++) ans.s[i][j] = MOD(ans.s[i][j] + s[i][k] * c.s[k][j], m); } } return ans; } }A; mat powMat (int n) { mat ans; ans.set (1, 0, 0, 1); while (n) { if (n&1) ans = ans * A; n /= 2; A = A * A; } return ans; } int main () { int a, b, n; while (scanf("%d%d%d%d", &a, &b, &n, &m) == 4) { double t = pow (a + sqrt(b), 2); ll s1 = 2 * a % m; ll s2 = (ll)ceil(t) % m; if (n <= 1) { printf("%lld\n", s1); } else { A.set (2 * a, b - a * a, 1, 0); mat ans = powMat (n-2); printf("%lld\n", MOD(s2 * ans.s[0][0] + s1 * ans.s[0][1], m)); } } return 0; }