数学推导,矩阵快速幂
题目连接。。。
题目涉及n次方,自然想到用矩阵的快速幂来简化操作,把根号的部分和整数部分分开考虑,不难得出矩阵 [a,b; 1,a],初始的数为[a,1]
但是这样一来最后的结果中就要涉及开根号,由于在矩阵幂运算中要mod m ,所以开根号后肯定会出错。
幸好网上有大神提供了一种猜想,即整数部分和带根号的部分向上取整的值相同,证明了下,还真是这样。。。
[(a+b^0.5)^1] = 2*a
设 [x] == [y*b^0.5]
x = c
b^0.5 = a - 0.t
y *( a- 0.t) = c-0.n
则 1. a*x + b*y = ac + (a-0.t)*(c-0.n) = 2ac - 0.t*c - 0.n*a + 0.t*0.n
2. (x + a*y)*b^0.5 = (c+a*(c-0.n)/(a-0.t))*(a-0.t) = 2ac - 0.t*c - 0.n*a
所以 1. == 2. + 0.t*0.n
因为 1. 必为整数
所以 [1.] == [2.]
#include<stdio.h> #include <string.h> typedef __int64 ll; ll a, b, n, m; struct matrix { ll data[2][2]; matrix(bool c = false) { if (c) { memset(data, 0, sizeof data); data[0][0] = data[1][1] = 1; return; } data[0][0] = a; data[0][1] = b; data[1][0] = 1; data[1][1] = a; } matrix operator * (matrix &c) const { matrix tp; for (int i = 0; i< 2; i++) for (int k = 0; k< 2; k++) { tp.data[i][k] = 0; for (int j = 0; j< 2; j++) { tp.data[i][k] += data[i][j]*c.data[j][k]; tp.data[i][k] %= m; } } return tp; } }; matrix mPow(matrix v, ll t) { matrix tp(true); while (t) { if ( t&0x1) tp = tp*v; v = v*v; t>>=1; } return tp; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif while (scanf("%I64d%I64d%I64d%I64d", &a, &b, &n, &m) != EOF) { matrix k; k = mPow(k, n-1); ll res = (k.data[0][0]*a + k.data[0][1])%m; printf("%I64d\n", (res*2)%m); } return 0; }