题意
Fib数列为1,1,2,3,5,8…
求在Mod10^9+9的意义下,数字N在Fib数列中出现在哪个位置
无解输出-1
N < = 10^9+9
分析
第一次做跟二次剩余有关的题目。
斐波那契数列的通项是
Fn=(1+5√2)n−(1−5√2)n5√
。
设 t=(1+5√2)n,T=5√N
可以得到
t−(−1)n1t=5√N
两边同乘 t 可得
枚举 n 是偶数或奇数的情况,通过求根公式可以求出
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
typedef long long LL;
const int sq5=383008016;
const int ny2=500000005;
const int MOD=1000000009;
const int inf=0x7fffffff;
int n,w;
map<int,int> ma;
struct com
{
int x,y;
com operator * (const com &a) {return (com){((LL)x*a.x+(LL)y*a.y%MOD*w)%MOD,((LL)x*a.y+(LL)y*a.x)%MOD};}
};
int ksm(int x,int y)
{
int ans=1;
while (y)
{
if (y&1) ans=(LL)ans*x%MOD;
x=(LL)x*x%MOD;y>>=1;
}
return ans;
}
int sq(int n)
{
if (ksm(n,(MOD-1)/2)!=1) return 0;
int a=0;
while (ksm(((LL)a*a%MOD-MOD-n)%MOD,(MOD-1)/2)==1) a=rand();
com x=(com){a,MOD-1},ans=(com){1,0};int y=(MOD+1)/2;w=((LL)a*a%MOD+MOD-n)%MOD;
while (y)
{
if (y&1) ans=ans*x;
x=x*x;y>>=1;
}
return ans.x;
}
int BSGS(int t,int n)
{
int block=sqrt(MOD),ny=ksm(t,MOD-2),tmp=n;
ma.clear();
ma[n]=MOD;
for (int i=1;i<block;i++) tmp=(LL)tmp*ny%MOD,ma[tmp]=!ma[tmp]?i:ma[tmp];
if (ma[1]) return ma[1]%MOD;
tmp=1;t=ksm(t,block);
for (int i=1;i<=block;i++)
{
tmp=(LL)tmp*t%MOD;
if (ma[tmp]) return (i*block+ma[tmp])%MOD;
}
return -1;
}
int main()
{
scanf("%d",&n);
int t=(LL)(sq5+1)*ny2%MOD,T=(LL)sq5*n%MOD;
int ans=inf,x,y,r0=sq((LL)5*n*n%MOD+4),r1=sq((LL)5*n*n%MOD-4);
x=(LL)(T+r0)*ny2%MOD;y=BSGS(t,x);
if (y>-1&&!(y&1)&&r0) ans=min(ans,y);
x=(LL)(T+MOD-r0)*ny2%MOD;y=BSGS(t,x);
if (y>-1&&!(y&1)&&r0) ans=min(ans,y);
x=(LL)(T+r1)*ny2%MOD;y=BSGS(t,x);
if (y>-1&&(y&1)&&r1) ans=min(ans,y);
x=(LL)(T+MOD-r1)*ny2%MOD;y=BSGS(t,x);
if (y>-1&&(y&1)&&r1) ans=min(ans,y);
if (ans==inf) puts("-1");
else printf("%d",ans);
return 0;
}