写在最前面,方便复习:
已知数列
{
a
n
}
\{a_n\}
{an} 其满足递推式
a
n
+
2
=
c
1
a
n
+
1
+
c
2
a
n
a_{n+2} = c_1a_{n+1}+c_2a_n
an+2=c1an+1+c2an 其中
c
1
,
c
2
c_1,c_2
c1,c2 为常数且
c
2
≠
0
c_2 \not =0
c2=0
记
x
2
=
c
1
x
+
c
2
x^2=c_1x+c_2
x2=c1x+c2 的两根为
x
1
,
x
2
x_1,x_2
x1,x2 ,此时有:
- x 1 ≠ x 2 x1\not= x_2 x1=x2 时, a n = b 1 x 1 n + b 2 x 2 n a_n=b_1x_1^n+b_2x_2^n an=b1x1n+b2x2n , b 1 , b 2 b_1,b_2 b1,b2 满足 { a 1 = b 1 x 1 + b 2 x 2 a 2 = b 1 x 1 2 + b 2 x 2 2 \left \{ \begin{array}{c} a_1=b_1x_1+b_2x_2\\ a_2=b_1x_1^2+b_2x_2^2\\ \end{array} \right. {a1=b1x1+b2x2a2=b1x12+b2x22
- x 1 = x 2 = x x1= x_2=x x1=x2=x 时, a n = b 1 x 1 n + b 2 x 2 n a_n=b_1x_1^n+b_2x_2^n an=b1x1n+b2x2n , b 1 , b 2 b_1,b_2 b1,b2 满足 { a 1 = ( b 1 + b 2 ) x a 2 = ( b 1 + b 2 ) x 2 \left \{ \begin{array}{c} a_1=(b_1+b_2)x\\ a_2=(b_1+b_2)x^2\\ \end{array} \right. {a1=(b1+b2)xa2=(b1+b2)x2
题目链接:点击这里
题目大意:
t
t
t 组输入,每组输入给定正整数
x
(
1
≤
x
<
2
32
)
x(1\le x < 2^{32})
x(1≤x<232) ,和质数
p
(
p
≤
46337
)
p(p\le 46337)
p(p≤46337) 求:
⌊
y
=
(
5
+
2
6
)
1
+
2
x
⌋
m
o
d
p
\lfloor y=(5+2\sqrt6)^{1+2x}\rfloor \mod p
⌊y=(5+26)1+2x⌋modp
题目分析:
设
x
1
=
5
+
2
6
,
x
2
=
5
−
2
6
x_1=5+2\sqrt6,x_2=5-2\sqrt6
x1=5+26,x2=5−26 ,则这两根显然是方程
x
2
−
10
x
+
1
=
0
x^2-10x+1=0
x2−10x+1=0 的两根
故其递推方程为
a
n
+
2
=
10
a
n
+
1
−
a
n
a_{n+2}=10a_{n+1}-a_n
an+2=10an+1−an ,其通项为
a
n
=
(
5
+
2
6
)
n
+
(
5
−
2
6
)
n
a_n=(5+2\sqrt6)^n+(5-2\sqrt6)^n
an=(5+26)n+(5−26)n
因为
5
−
2
6
<
1
5-2\sqrt6 < 1
5−26<1 ,所以
(
5
−
2
6
)
n
<
1
(5-2\sqrt6)^n<1
(5−26)n<1 ,所以题目所求就是
a
n
−
1
a_n-1
an−1
因为此题模数不到
1
e
5
1e5
1e5 所以循环节不会很长可以直接暴力算出,但是如果模数很大则需要构造矩阵来求循环节,具体方法点击这里
之所以要找循环节是因为
2
x
2^x
2x 很大 对于每一个模数都存在循环节,这样就可以避免直接进行幂次运算
具体细节见代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
ll read()
{
ll res = 0,flag = 1;
char ch = getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = getchar();
}
while(ch>='0' && ch<='9')
{
res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
ch = getchar();
}
return res*flag;
}
const int maxn = 1e5+5;
ll mod;
const double pi = acos(-1);
const double eps = 1e-8;
ll n,cnt,a[maxn],loop[maxn];
ll get_loop()
{
a[0] = 2%mod,a[1] = 10%mod;
for(int i = 2;i < maxn;i++)
{
a[i] = (10*a[i-1]%mod-a[i-2]+mod)%mod;
if(a[i] == a[1] && a[i-1] == a[0])
return i-1;
}
}
ll qpow(ll a,ll b,ll mod)
{
ll res = 1;
while(b)
{
if(b&1) res = res*a%mod;
a = a*a%mod;
b >>= 1;
}
return res;
}
int main()
{
ll t = read();
while(t--)
{
n = read(),mod = read();
if(!loop[mod]) loop[mod] = get_loop(); //这里要记忆化一下不然就t掉了
ll pos = (1+qpow(2,n,loop[mod]))%loop[mod];
for(int i = 2;i <= pos;i++) //因为记忆化过所以上次get_loop 不一定枚举到了pos,所以需要重新扫一遍
a[i] = (10*a[i-1]%mod-a[i-2]+mod)%mod;
printf("Case #%lld: %lld\n",++cnt,(a[pos]-1+mod)%mod);
}
return 0;
}