1. 程式人生 > >【codechef】FN/Fibonacci Number

【codechef】FN/Fibonacci Number

.html 記得 opera ios sin register null 算法學習 inline

題意

給出 c 和 P ,求最小的非負整數 n 使得 \(Fib(n)=c(mod~ P)\)

其中 P 是質數且 模 10 等於一個完全平方數(也就是說 P 的末位是個完全平方數,那麽只能是 1 或者 9 )

(這裏的 Fib 指的就是斐波那契數列)

前置芝士

  1. Cipolla (attack 巨巨寫的炒雞好,%%%)
  1. BSGS (Judge 菜雞寫的炒雞爛,踩踩踩)

noteskey

不知道怎麽做,只能黈力呢...

我們發現斐波那契數列第 n 項是:

\[{1\over \sqrt5}\Big(\big( { 1 +\sqrt 5 \over 2 }\big)^n-\big( {1-\sqrt 5 \over 2} \big)^n \Big) \]

然後的話我們令 g 表示\(1\over \sqrt5\), q 表示 \({1+\sqrt5\over 2}\) , \(-{1\over q}\) 表示 \(1-\sqrt 5\over 2\)

這樣的話原本的式子就是:

\[q^n-(-q)^{-n}=cg (mod\ P)\]

\(x=q^n\) ,那麽繼續轉式子:

\[x- {(-1)^{n}\over x}=cg (mod\ P)\]

\[x^2- cgx -(-1)^{n}=0(mod\ P)\]

然後的話我們就可以求根公式了:

\[x={-cg±\sqrt{(cg)^2+4(-1)^n}\over 2}\]

這樣我們就可以先假設 n 的奇偶性, \(Cipolla\)

求出根號裏的東西然後中間的 正負號都取一遍,這樣 x 的值已經固定了,然後我們 bsgs 求出滿足當前枚舉的奇偶性的 n ,答案就出來了呢(最小非負整數的話就四者取個 min 就好了呢)

上面還有一個問題: 5 萬一不是 模 P 意義下的二次剩余怎麽辦...

這個問題不用擔心,題目保證了 \(P\%10=1 ~~ or~~ 9\) ,也就是說 \(P\%5=± 1\) ,據說滿足 \(P\%x=±1\) 的 x 是模 P 的二次剩余?不知道為什麽的說...

總之我們套兩個板子就可以 A 掉此題了 QWQ

code

雖說不曉得為什麽 \(\omega\) 這個虛部當成向量的第二維默認為 1 個單位就是了

而且 \(BSGS\) 裏面的 \(sqrt\) 我一開始寫成 \(Sqrt\) 了呢,是不是沒救了呢...

另外註意這裏的 \(mod\) 範圍 \(2e9\)\(inc\) 裏面千萬記得加上 \(0ll\) 不然可能要調很久...(和我一樣)

//by Judge
#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#define Rg register
#define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(Rg int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(Rg int i=head[u],v=e[i].to;i;v=e[i=e[i].nxt].to)
#define ll long long
using namespace std;
const int inf=0x7fffffff;
const int M=1e5+3;
typedef int arr[M];
#ifndef Judge
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
char buf[1<<21],*p1=buf,*p2=buf;
inline void cmin(int& a,int b){a=a<b?a:b;}
inline int read(){ int x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
} char sr[1<<21],z[20];int CCF=-1,Z;
inline void Ot(){fwrite(sr,1,CCF+1,stdout),CCF=-1;}
inline void print(int x,char chr='\n'){
    if(CCF>1<<20)Ot();if(x<0)sr[++CCF]=45,x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++CCF]=z[Z],--Z);sr[++CCF]=chr;
} int c,s,p,w,a,mod,inv2,res,rt;
inline int dec(int x,int y){return x<y?x-y+mod:x-y;}
inline int inc(int x,int y){return 0ll+x+y>=mod?0ll+x+y-mod:x+y;}
inline int mul(int x,int y){return 1ll*x*y-1ll*x*y/mod*mod;}
inline int qpow(Rg int x,Rg int p,Rg int s=1){
    for(;p;p>>=1,x=mul(x,x)) if(p&1) s=mul(s,x); return s;
}
struct cp{ int x,y; inline cp(Rg int xx,Rg int yy){x=xx,y=yy;}
    inline cp operator *(const cp& b)const{ //有點鬼畜不知原理的向量乘操作呢 
        return cp(inc(mul(x,b.x),mul(w,mul(y,b.y))),inc(mul(x,b.y),mul(y,b.x)));
    }
};
inline int qpow(Rg cp x,Rg int p){ Rg cp s(1,0); //向量快速乘?【逃 
    for(;p;p>>=1,x=x*x) if(p&1) s=s*x; return s.x;
}
inline int Sqrt(int x){ if(!x) return 0; // 0 的情況返回 0 就好了 
    if(qpow(x,(mod-1)>>1)==mod-1) return -1; // 無解返回 -1 
    while(1){ a=mul(rand(),rand()),w=dec(mul(a,a),x);
        if(qpow(w,(mod-1)>>1)==mod-1) return qpow(cp(a,1),(mod+1)>>1);
    }
}
const int N=262144;
struct Hash{ int pat,head[N]; struct Edge{int to,nxt,w; }e[N];  //hash 手打 map ?【霧 
    inline void clr(){memset(head,0,sizeof head),pat=0;}
    inline void add(int v,int w){e[++pat]={v,head[v&262143],w},head[v&262143]=pat;}
    inline int query(int x){go(x&262143)if(v==x)return e[i].w;return -1;}
}mp[2];
inline int bsgs(int x,int v,int tp){ //這裏傳的 tp 值是為了限制答案 n 的奇偶性 
    int m=sqrt(mod)+1; mp[0].clr(),mp[1].clr();
    for(Rg int i=1,res=mul(v,x);i<=m;++i,res=mul(res,x)) mp[i&1].add(res,i);
    for(Rg int i=1,tmp=qpow(x,m),res=tmp;i<=m;++i,res=mul(res,tmp))
        if(mp[i*m&1^tp].query(res)!=-1) return i*m-mp[(i*m)&1^tp].query(res);
    return inf;
}
int main(){ srand(time(NULL)); int T=read();
    for(;T;--T){
        c=read(),mod=read(),s=Sqrt(5),inv2=(mod+1)>>1;
        p=mul(s+1,inv2),c=mul(c,s),res=inf;
        
        rt=Sqrt((1ll*c*c+4)%mod); //第一種可能 
        if(rt>=0) cmin(res,bsgs(p,mul(inc(c,rt),inv2),0)), //再來兩種可能 
            cmin(res,bsgs(p,mul(dec(c,rt),inv2),0));
        
        rt=Sqrt((1ll*c*c+mod-4)%mod); //第二種可能 
        if(rt>=0) cmin(res,bsgs(p,mul(inc(c,rt),inv2),1)), //然後又是兩個可能 
            cmin(res,bsgs(p,mul(dec(c,rt),inv2),1));
        print(res<inf?res:-1);
    } return Ot(),0;
}

【codechef】FN/Fibonacci Number