「Codechef FN」Fibonacci Number

传送门


problem

F i F_i Fi 表示斐波那契数列:

{ F n = n , n ≤ 1 F n = F n − 1 + F n − 2 , o t h e r w i s e \begin{cases} F_n=n ,&n ≤ 1\\ F_n=F_{n-1}+F_{n-2}, &\mathrm{otherwise} \end{cases} {Fn=n,Fn=Fn1+Fn2,n1otherwise

给定 c c c p p p,求满足 F n ≡ c ( m o d p ) F_n\equiv c\pmod p Fnc(modp) 的最小的 n n n

保证 11 ≤ p ≤ 2 × 1 0 9 11\le p\le2\times10^9 11p2×109 p p p 是素数,且 p   m o d   10 p\bmod 10 pmod10 是一个完全平方数。


solution

首先,斐波那契数列是有通项公式的:

F n = 1 5 ( ( 1 + 5 2 ) n − ( 1 − 5 2 ) n ) F_n=\frac1{\sqrt 5}\left((\frac{1+\sqrt 5}{2})^n-(\frac{1-\sqrt 5}{2})^n\right) Fn=5 1((21+5 )n(215 )n)

那么设 φ = 1 + 5 2 \varphi=\frac{1+\sqrt 5}2 φ=21+5 ,那么 − 1 φ = 1 − 5 2 -\frac 1\varphi=\frac{1-\sqrt5}{2} φ1=215 ,那么相当于是解:

1 5 ( φ n − ( − 1 φ ) n ) ≡ c ( m o d p ) φ n − ( − 1 ) n φ n ≡ 5 c ( m o d p ) \begin{aligned} \frac{1}{\sqrt 5}(\varphi^n-(-\frac 1 \varphi)^n)&\equiv c\pmod p \\\varphi^n-\frac{(-1)^n}{\varphi^n}&\equiv \sqrt5c\pmod p \end{aligned} 5 1(φn(φ1)n)φnφn(1)nc(modp)5 c(modp)

又令 ϕ = φ n \phi=\varphi^n ϕ=φn,继续化简,有:

ϕ − ( − 1 ) n ϕ ≡ 5 c ( m o d p ) \phi-\frac{(-1)^n}{\phi}\equiv \sqrt5c\pmod p ϕϕ(1)n5 c(modp)

然后用个求根公式就可以解出 ϕ \phi ϕ

ϕ ≡ 5 c ± 5 c 2 + 4 ( − 1 ) n 2 ( m o d p ) \phi\equiv\frac{\sqrt 5c\pm\sqrt{5c^2+4(-1)^n}}{2} \pmod p ϕ25 c±5c2+4(1)n (modp)

那么用二次剩余就可以解 ϕ \phi ϕ 了,又由于 ϕ = φ n \phi=\varphi^n ϕ=φn,再套个 BSGS n n n 即可。注意解得时候要特判 n n n 的奇偶性来解。

然后 5 5 5 是模 p p p 意义下的二次剩余,直接解就可以了。

由于 p p p 是素数,且 p   m o d   10 p \bmod 10 pmod10 是完全平方数,所以 p = ± 1 ( m o d 5 ) p=\pm1\pmod 5 p=±1(mod5),那么 p 5 − 1 2 = 1 p^{\frac{5-1}2}=1 p251=1,即 p p p 是模 5 5 5 意义下的二次剩余。
根据二次互反律,设 p , q p,q p,q 是不同的奇素数,有:

( p q ) ( q p ) = ( − 1 ) p − 1 2 q − 1 2 \left(\frac pq\right)\left(\frac qp\right)=(-1)^{\frac{p-1}2\frac{q-1}2} (qp)(pq)=(1)2p12q1

其中 ( p q ) \left(\frac pq\right) (qp)勒让德符号
那么把 5 5 5 p p p 代进上式,就不难发现 5 5 5 是模 p p p 意义下的二次剩余。


code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int T,C,P,s5,U,V;
int add(int x,int y)  {return (ll)x+y>=P?(ll)x+y-P:x+y;}
int dec(int x,int y)  {return (ll)x-y< 0?(ll)x-y+P:x-y;}
int mul(int x,int y)  {return (ll)x*y>=P?(ll)x*y%P:x*y;}
int power(int a,int b){
	int ans=1;
	for(;b;b>>=1,a=mul(a,a))  if(b&1)  ans=mul(ans,a);
	return ans;
}
int Inv(int x)  {return power(x,P-2);}
void Max(int &x,int y)  {if(x<y)x=y;}
void Min(int &x,int y)  {if(x>y)x=y;}
namespace Cipolla{
	int I,val;
	struct num{
		int x,y;
		num(int x=0,int y=0):x(x),y(y){}
		friend num operator*(const num &a,const num &b){
			return num(add(mul(a.x,b.x),mul(val,mul(a.y,b.y))),add(mul(a.y,b.x),mul(a.x,b.y)));
		}
		friend num operator^(num a,int b){
			num ans(1,0);
			for(;b;b>>=1,a=a*a)  if(b&1)  ans=ans*a;
			return ans;
		}
	};
	int Sqrt(int n){
		if(!n)  return 0;
		if(power(n,(P-1)>>1)==P-1)  return -1;
		while(1){
			I=rand(),val=dec(mul(I,I),n);
			if(power(val,(P-1)>>1)==P-1)  break;
		}
		return (num(I,1)^((P+1)>>1)).x;
	}
}
using Cipolla::Sqrt;
unordered_map<int,int>Hash;
int BSGS(int a,int b,int type){
	Hash.clear();
	int now=b,t=ceil(sqrt(P));
	for(int i=0;i<t;++i)  Hash[now]=i,now=mul(now,a);
	now=1,a=power(a,t);
	if(!a)  return b?P+1:1;
	for(int i=0,pos;i<=t;++i){
		pos=(Hash.find(now)==Hash.end())?-1:Hash[now],now=mul(now,a);
		if(pos>=0&&i*t-pos>=0&&((i*t-pos)&1)==type)  return i*t-pos;
	}
	return P+1;
}
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&C,&P);
		s5=Sqrt(5),U=mul(add(1,s5),Inv(2)),V=mul(C,s5);
		int d1=add(mul(V,V),4),d2=dec(mul(V,V),4),ans=P+1;
		if(!d1||power(d1,(P-1)>>1)==1){
			int tmp=Sqrt(d1),val;
			val=mul(add(V,tmp),Inv(2)),Min(ans,BSGS(U,val,0));
			val=mul(dec(V,tmp),Inv(2)),Min(ans,BSGS(U,val,0));
		}
		if(!d2||power(d2,(P-1)>>1)==1){
			int tmp=Sqrt(d2),val;
			val=mul(add(V,tmp),Inv(2)),Min(ans,BSGS(U,val,1));
			val=mul(dec(V,tmp),Inv(2)),Min(ans,BSGS(U,val,1));
		}
		printf("%d\n",ans==P+1?-1:ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值