Codechef:Fibonacci Number/FN——求通项+二次剩余+bsgs
Posted lfri
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codechef:Fibonacci Number/FN——求通项+二次剩余+bsgs相关的知识,希望对你有一定的参考价值。
题意
定义 $F_n$ 为
$$F_n = \\left\\\\beginmatrix
0, n=0\\\\
1, n=1 \\\\
F_n-1 + F_n-2, n > 1
\\endmatrix\\right.$$
现给你一个素数 $p$ 和一个非负整数 $C$,你需要最小的非负整数 $n$,使得 $F_n \\equiv C (mod \\ p)$.
分析
因为题目保证 $p \\ mod \\ 10$ 是一个完全平方数,也就是说 $p \\ mod \\ 5$ 等于1或-1,即5是模$p$ 的二次剩余(据说)。
求出通项,用Cipolla求出5的二次剩余,记为 $c$,并记 $p = \\frac1+c2$,
通项变成
$$1\\over c\\left(p^n-(-1)^n1\\over p^n\\right)\\equiv a\\pmodP$$
解得
$$p^n\\equiv ac\\pm \\sqrtac+4(-1)^n\\over 2$$
然后枚举一下 $n$ 的奇偶性,再用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 egint 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;
参考链接:https://www.cnblogs.com/bztMinamoto/p/10664967.html
以上是关于Codechef:Fibonacci Number/FN——求通项+二次剩余+bsgs的主要内容,如果未能解决你的问题,请参考以下文章
@codechef - RNG@ Random Number Generator
LeetCode 509. Fibonacci Number
[LeetCode] 509. Fibonacci Number