题目大意
求fib(n) mod 10^9+9=k的最小n。
做法
我们知道
fib(n)=1√5∗[(1+√52)n−(1−√52)n]
不妨设两个特征根分别为a和b,注意
ab=−1
根号5在1e9+9下是存在的,设为g,那么问题变为
an−bn=gk
的最小n。
an−(−1)nan=gk
a2n−gkan−(−1)n=0
an=gk+√(5k2+4∗(−1)n)2
不妨分类讨论n为奇数还是偶数,求出根号后变成bsgs问题(只要求解出某个奇偶性的最小n)。
开根号怎么做?可以求出原根然后bsgs。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
map<int,int> s;
const int p=1000000009,g=383008016,inv2=(p+1)/2,maxn=1000000+10,gg=13;
int fib[maxn];
int i,j,k,l,r,t,n,m,q,x,y,z,a,b,ans;
bool czy;
int qsm(int x,int y){
if (!y) return 1;
int t=qsm(x,y/2);
t=(ll)t*t%p;
if (y%2) t=(ll)t*x%p;
return t;
}
int bsgs(int a,int b,int f){
if (f==0&&b==1) return 0;
int i,k,t=1,r,ans=-1;
q=floor(sqrt(p));
r=qsm(a,q);
//s.clear();
fo(i,1,q){
t=(ll)t*r%p;
if (!s[t]) s[t]=i;
}
t=1;
fo(i,0,q-1){
//t=qsm(a,i);
r=(ll)b*t%p;
t=(ll)t*a%p;
k=s[r];
if (k){
k=k*q-i;
if (k%2!=f) continue;
if (ans==-1||k<ans) ans=k;
}
//t=(ll)t*a%p;
}
r=qsm(a,q);
t=1;
fo(i,1,q){
t=(ll)t*r%p;
s[t]=0;
}
return ans;
}
bool pd(int n){
/*x=bsgs(gg,n,0);
if (x==-1) return 0;else return 1;*/
if (qsm(n,(p-1)/2)==1) return 1;else return 0;
}
int main(){
freopen("rabbit.in","r",stdin);freopen("rabbit.out","w",stdout);
czy=1;
/*fib[0]=0;
fib[1]=1;
fo(i,2,maxn-10) fib[i]=(fib[i-1]+fib[i-2])%p;*/
scanf("%d",&k);
fo(i,0,maxn-9)
if (i>maxn-10||fib[i]==k) break;
if (i<=maxn-10){
printf("%d\n",i);
return 0;
}
ans=-1;
a=(ll)(1+g)*inv2%p;
b=(ll)(1-g)*inv2%p;
l=(ll)5*k%p*k%p*qsm(4,p-2)%p;
m=l-1;
(m+=p)%=p;
if (pd(m)){
x=bsgs(gg,m,0);
x/=2;
z=y=qsm(gg,x);
(y+=(ll)g*k%p*inv2%p)%=p;
(y+=p)%=p;
(a+=p)%=p;
n=bsgs(a,y,1);
if (n!=-1) ans=n;
y=-z;
(y+=(ll)g*k%p*inv2%p)%=p;
(y+=p)%=p;
(a+=p)%=p;
n=bsgs(a,y,1);
if (n!=-1&&(ans==-1||n<ans)) ans=n;
}
m=l+1;
(m+=p)%=p;
if (pd(m)){
x=bsgs(gg,m,0);
x/=2;
z=y=qsm(gg,x);
(y+=(ll)g*k%p*inv2%p)%=p;
(y+=p)%=p;
(a+=p)%=p;
n=bsgs(a,y,0);
if (n!=-1&&(ans==-1||n<ans)) ans=n;
y=-z;
(y+=(ll)g*k%p*inv2%p)%=p;
(y+=p)%=p;
(a+=p)%=p;
n=bsgs(a,y,0);
if (n!=-1&&(ans==-1||n<ans)) ans=n;
}
printf("%d\n",ans);
//printf("%d\n",bsgs(gg,500000001,1));
}