看来我数学还是太弱了,这道题也没有想到。
我们发现
(b+d√2)n
(
b
+
d
2
)
n
是个无理数,而且这个数非常大,所以无法直接计算。我们又发现
(b−d√2)n
(
b
−
d
2
)
n
的值虽然是个无理数,但是他的值向下取整之后非常好计算。然后我们又发现,
(b+d√2)n+(b−d√2)n
(
b
+
d
2
)
n
+
(
b
−
d
2
)
n
是个有理数,又因为
b mod 2=1,d mod 4=1
b
m
o
d
2
=
1
,
d
m
o
d
4
=
1
,所以不难证明这个数是一个整数。
所以,我们可以将问题转变为求
⌊[(b+d√2)n+(b−d√2)n]−(b−d√2)n⌋
⌊
[
(
b
+
d
2
)
n
+
(
b
−
d
2
)
n
]
−
(
b
−
d
2
)
n
⌋
然后我们就可以把问题拆成两部分。
首先我们考虑第一部分。我们可以构造一个一元二次方程:
x2−b+b2−d4=0
x
2
−
b
+
b
2
−
d
4
=
0
,那么它的解
x1=b+d√2,x2=b−d√2
x
1
=
b
+
d
2
,
x
2
=
b
−
d
2
。
那么第一部分就等于
xn1+xn2
x
1
n
+
x
2
n
然后我们把这个式子变形一下就可以得到:
xn1+xn2=(x1+x2)(xn−11+xn−12)−x1x2(xn−21+xn−22)
x
1
n
+
x
2
n
=
(
x
1
+
x
2
)
(
x
1
n
−
1
+
x
2
n
−
1
)
−
x
1
x
2
(
x
1
n
−
2
+
x
2
n
−
2
)
然后令
F(n)=xn1+xn2
F
(
n
)
=
x
1
n
+
x
2
n
,
可以得到
F(n)=(x1+x2)F(n−1)−x1x2F(n−2)
F
(
n
)
=
(
x
1
+
x
2
)
F
(
n
−
1
)
−
x
1
x
2
F
(
n
−
2
)
然后我们构造的一元二次方程就派上用场了!
根据韦达定理,对于一个一元二次方程
ax2+bx+c=0
a
x
2
+
b
x
+
c
=
0
的两个解
x1,2
x
1
,
2
满足:
x1+x2=−ba,x1x2=ca
x
1
+
x
2
=
−
b
a
,
x
1
x
2
=
c
a
所以
F(n)=bF(n−1)+d−b22F(n−2)
F
(
n
)
=
b
F
(
n
−
1
)
+
d
−
b
2
2
F
(
n
−
2
)
其中
F(0)=2,F(1)=b
F
(
0
)
=
2
,
F
(
1
)
=
b
推到这里就是非常经典的的矩乘快速递推啦!
对于第二部分,
∵b2≤d<(b+1)2
∵
b
2
≤
d
<
(
b
+
1
)
2
又
∵b,d∈N
∵
b
,
d
∈
N
∴b≤d−−√<b+1
∴
b
≤
d
<
b
+
1
∴b−d√2∈(−1,0]
∴
b
−
d
2
∈
(
−
1
,
0
]
不难发现,当且仅当
n
n
为奇数且时,这一部分对答案有
−1
−
1
的贡献。所以我们判一下是否减
1
1
就行了。
有一个坑点,这个模数非常大,加起来可能会爆,所以我们加的时候要判一下它们的和是否小于
0
0
。
注意两个数相乘会爆,所以要用快速乘。
快速乘其实主要就是利用
long double
l
o
n
g
d
o
u
b
l
e
的较高的精度,再利用我们小学学的一个东西(被除数减除数乘商等于余数),就可以在
O(1)
O
(
1
)
的时间内完成较大的数的乘法并取模。
如果有错在评论区吼一声哦!
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll mod=7528443412579576937ll;
ll b,d,n;
ll Add(ll x,ll y){
return x+y>=mod||x+y<0?x+y-mod:x+y;
}
ll Minus(ll x,ll y){
return x-y<0?x-y+mod:x-y;
}
ll Mul(ll x,ll y){
ll d=(ll)(x*(long double)y/mod+0.5);
return Minus(x*y,d*mod);
}
struct Matrix{
ll a[2][2];
ll *operator[](int b){
return a[b];
}
friend Matrix operator*(Matrix A,Matrix B){
Matrix ret;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++){
ret[i][j]=0;
for(int k=0;k<2;k++)
ret[i][j]=Add(ret[i][j],Mul(A[i][k],B[k][j]));
}
return ret;
}
Matrix operator*=(Matrix B){
*this=*this*B;
return *this;
}
}A,B;
Matrix qpow(Matrix x,ll n){
Matrix ret;
ret[0][0]=ret[1][1]=1,ret[0][1]=ret[1][0]=0;
while(n){
if(n&1ll)
ret*=x;
x*=x;
n>>=1ll;
}
return ret;
}
int main(){
scanf("%lld%lld%lld",&b,&d,&n);
if(!n){
puts("1");
return 0;
}
A[0][0]=b;
A[0][1]=2;
B[0][0]=b;
B[0][1]=1;
B[1][0]=(d-b*b)/4;
A[1][0]=A[1][1]=B[1][1]=0;
A*=qpow(B,n-1);
printf("%lld",Minus(A[0][0],!(n&1ll)&&(d!=b*b)));
return 0;
}