Codechef:Fibonacci Number/FN(二次剩余+bsgs)

题面

传送门

前置芝士

\(bsgs\)\(Cipolla\)

题解

因为题目保证\(p\bmod 10\)是完全平方数,也就是说\(p\bmod 5\)等于\(1\)\(-1\),即\(5\)是模\(p\)的二次剩余(法老讲过,我忘了为啥了……)

然后我们需要用\(Cipolla\)求出\(c=\sqrt{5}\),并记\(p={1+c\over 2}\)

用斐波那契数列的通项公式代入,方程可以变为

\[{1\over c}\left(p^n-(-1)^n{1\over p^n}\right)\equiv a\pmod{P} \]

解得

\[p^n\equiv {ac\pm \sqrt{ac+4(-1)^n}\over 2} \]

我们枚举一下\(n\)的奇偶性,开根可以用\(Cipolla\)处理,然后用\(bsgs\)解得\(n\)就可以了

//minamoto
#include<bits/stdc++.h>
#define R register
#define inf 0x7fffffff
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
    if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
int P;
inline int add(R int x,R int y){return 0ll+x+y>=P?0ll+x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
	R int res=1;
	for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
	return res;
}
int w,a;
struct cp{
	int x,y;
	inline cp(R int _x,R int _y):x(_x),y(_y){}
	inline cp operator *(const cp &b)const{
		return cp(add(mul(x,b.x),mul(w,mul(y,b.y))),add(mul(x,b.y),mul(y,b.x)));
	}
};
int ksm(R cp x,R int y){
	R cp res(1,0);
	for(;y;y>>=1,x=x*x)if(y&1)res=res*x;
	return res.x;
}
int Sqrt(int x){
	if(!x)return 0;
	if(ksm(x,(P-1)>>1)==P-1)return -1;
	while(true){
		a=mul(rand(),rand()),w=dec(mul(a,a),x);
		if(ksm(w,(P-1)>>1)==P-1)return ksm(cp(a,1),(P+1)>>1);
	}
}
const int N=262144;
struct Hash{
	struct eg{int v,nx,w;}e[N];int head[N],tot;
	inline void clr(){memset(head,0,sizeof(head)),tot=0;}
	inline void add(R int v,R int w){e[++tot]={v,head[v&262143],w},head[v&262143]=tot;}
	int query(int x){
		go(x&262143)if(v==x)return e[i].w;
		return -1;
	}
}mp[2];
int bsgs(int x,int v,int sgn){
	int m=sqrt(P)+1;mp[0].clr(),mp[1].clr();
	for(R int i=1,res=mul(v,x);i<=m;++i,res=mul(res,x))mp[i&1].add(res,i);
	for(R int i=1,tmp=ksm(x,m),res=tmp;i<=m;++i,res=mul(res,tmp))
		if(mp[(i*m)&1^sgn].query(res)!=-1)return i*m-mp[(i*m)&1^sgn].query(res);
	return inf;
}
int c,s,p,inv2,res,rt;
int main(){
	srand(time(NULL));
//	freopen("testdata.in","r",stdin);
	for(int T=read();T;--T){
		c=read(),P=read(),s=Sqrt(5),inv2=(P+1)>>1,p=mul(s+1,inv2),c=mul(c,s);
		res=inf;
		rt=Sqrt((1ll*c*c+4)%P);
		if(rt!=-1){
			cmin(res,bsgs(p,mul(add(c,rt),inv2),0)),
			cmin(res,bsgs(p,mul(dec(c,rt),inv2),0));
		}
		rt=Sqrt((1ll*c*c+P-4)%P);
		if(rt!=-1){
			cmin(res,bsgs(p,mul(add(c,rt),inv2),1)),
			cmin(res,bsgs(p,mul(dec(c,rt),inv2),1));
		}
		printf("%d\n",res==inf?-1:res);
	}
	return 0;
}
posted @ 2019-04-07 12:46  bztMinamoto  阅读(611)  评论(0编辑  收藏  举报
Live2D