数学推导,矩阵快速幂
题目涉及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;
}