Description
B 君有两个好朋友,他们叫宁宁和冉冉。有一天,冉冉遇到了一个有趣的题目:输入 b;d;n,求
Input
一行三个整数 b;d;n
Output
一行一个数表示模 7528443412579576937 之后的结果。
Sample Input
1 5 9
Sample Output
76
HINT
其中 0<b2<=d<(b+1)2<=1018,n<=1018 ,并且 b mod 2=1,d mod 4=1
Solution
看看题目中的式子,想想初中数学,是不是很熟悉啊?
没错,他很像是一元二次方程的根。再联想一下n次方,于是神奇的发现他又像是某数列通项公式中的那个东东。
式子中可以看出,如果一元二次方程
x2=px+q
的一个根为
(b+d√2)n
,那么
Δ=p2+4q=d
,
p=−b
,所以根据通项公式可以构造出序列:
an=b∗an−1+(d−b2)4∗an−2
他的通项公式为
an=A(b+d‾‾√2)n+B(b−d‾‾√2)n
为了方便计算,我们取 A=B=1 ,所以
a0=2
a1=b
而序列a的递推式中 (d−b2)4 ,由于b mod 2=1,d mod 4=1,所以 (d−b2)4 一定是整数,所以矩阵乘法直接求出第n项,所以我们要的答案就是
(b+d‾‾√2)n=an−(b−d‾‾√2)n
由于题目中给出 b2<=d<(b+1)2 ,所以 b−d√2∈(−1,0] ,当且仅当 b2≠d 且n为偶数时对答案有-1的贡献,所以答案要视情况减一。
注意模数太大,所以要开unsigned long long,并且要用快速乘取模。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef unsigned long long LL;
const LL mod=7528443412579576937;
struct matrix{
LL a[2][2];
matrix(){memset(a,0,sizeof a);}
}temp,I,c;
LL b,d,n,ans;
LL ksc(LL x,LL y){
LL re=0;
while(y){
if(y&1)(re+=x)%=mod;
(x+=x)%=mod;y>>=1;
}
return re;
}
matrix cheng(matrix x,matrix y){
matrix re;
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
(re.a[i][j]+=ksc(x.a[i][k],y.a[k][j]))%=mod;
}
}
}
return re;
}
matrix pow(matrix x,LL y){
matrix re=I;
while(y){
if(y&1)re=cheng(re,x);
x=cheng(x,x);y>>=1;
}
return re;
}
int main(){
cin>>b>>d>>n;
I.a[0][0]=I.a[1][1]=1;
temp.a[0][0]=b;temp.a[0][1]=2;
c.a[0][0]=b;c.a[0][1]=1;c.a[1][0]=(d-b*b)/4;
if(n==0)return printf("1\n"),0;
temp=cheng(temp,pow(c,n-1));
ans=temp.a[0][0];
if(!(n&1)&&b*b!=d)ans--;
cout<<(ans+mod)%mod<<endl;
return 0;
}