今天来讲的是在欧拉工程上的一道递推题,题目描述如下链接。
题目:https://projecteuler.net/problem=492
当然,这道题在51Nod上有一个比较通用的版本,链接如下
题目:http://www.51nod.com/contest/problem.html#!problemId=1361
题意:给定,并且有,给定两个数和,求的值。其中
满足和,并且为素数。
分析:首先对原递推式进行变换得到
那么令,继而有,而。到了这里,假设
那么我们带入继续递推会发现一个神奇的结论
其中假设取其中一个解如下
那么得到如下
好了,到了这里,最直观的做法就是根据上述公式求出,然后会带回去求出即可。
如果想用二次剩余的方法来做,因为可能无解,所以不能用这种方法做。看成更一般
形式的求解,比如下面
那么回忆之前的一篇文章:http://blog.csdn.net/acdreamers/article/details/8994222,重
点是HDU4565题,这是明显可以构造矩阵的,具体如何构造不再赘述。然后先得到递推式如下
所以最终得到如下
可以看到矩阵的指数很大,所以需要降小,而这是一个经典的矩阵找寻环节问题。之前有篇文章,如下
链接:http://blog.csdn.net/acdreamers/article/details/25616461
当时那道题由于要求最小的循环节,所以要求比较精确,必须枚举因子。但是对于本题不同,我们只要能
求出一个合理的循环节即可,不要求最小的,因为不影响最终结果。
参照当时的结论,由于117不是素数,所以只有两种情况。
(1)如果117是的二次剩余时,最小循环节是的因子,我们可以取作为循环节。
(2)如果117是的二次非剩余时,最小循环节是的因子,可以取作
为循环节。
到了这里大部分问题都已经解决。实际上当117是的二次非剩余时,循环节可以为,至于为什么是
正确的,请来个大神证明! 另外为2或者3时,需要特判。
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
typedef long long LL;
const int N = 2;
struct Matrix
{
LL m[N][N];
};
Matrix I =
{
1, 0,
0, 1
};
LL quick_mod(LL a, LL b, LL m)
{
LL ans = 1;
a %= m;
while(b)
{
if(b & 1)
{
ans = ans * a % m;
b--;
}
b >>= 1;
a = a * a % m;
}
return ans;
}
LL Legendre(LL a, LL p)
{
LL t = quick_mod(a, (p - 1) >> 1, p);
if(t == 1) return 1;
return -1;
}
Matrix multi(Matrix a, Matrix b, LL m)
{
Matrix c;
for(int i = 0; i < N; i++)
{
for(int j = 0; j < N; j++)
{
c.m[i][j] = 0;
for(int k = 0; k < N; k++)
c.m[i][j] += a.m[i][k] * b.m[k][j] % m;
c.m[i][j] %= m;
}
}
return c;
}
Matrix power(Matrix A, LL k, LL m)
{
Matrix ans = I, p = A;
while(k)
{
if(k & 1)
{
ans = multi(ans, p, m);
k--;
}
k >>= 1;
p = multi(p, p, m);
}
return ans;
}
LL GetLoop(LL p)
{
if(Legendre(117, p) == -1)
return p + 1;
return p - 1;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
LL n, p;
scanf("%lld %lld", &n, &p);
if(p == 2 || p == 3)
{
puts("1");
continue;
}
Matrix A;
A.m[0][0] = 11 % p;
A.m[0][1] = p - 1;
A.m[1][0] = 1;
A.m[1][1] = 0;
LL loop = GetLoop(p);
LL x = quick_mod(2, n - 1, loop);
x = ((x - 1) % loop + loop) % loop;
Matrix ans = power(A, x, p);
LL res = (ans.m[1][0] * 119 % p + ans.m[1][1] * 11 % p) % p;
res = ((res - 5) % p + p) % p;
res = res * quick_mod(6, p - 2, p) % p;
printf("%lld\n", res);
}
return 0;
}