• 【codechef】FN/Fibonacci Number


    题意

    给出 c 和 P ,求最小的非负整数 n 使得 (Fib(n)=c(mod~ P))

    其中 P 是质数且 模 10 等于一个完全平方数(也就是说 P 的末位是个完全平方数,那么只能是 1 或者 9 )

    (这里的 Fib 指的就是斐波那契数列)

    前置芝士

    1. Cipolla (attack 巨巨写的炒鸡好,%%%)
    1. BSGS (Judge 菜鸡写的炒鸡烂,踩踩踩)

    noteskey

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

    我们发现斐波那契数列第 n 项是:

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

    然后的话我们令 g 表示(1over sqrt5), q 表示 ({1+sqrt5over 2}) , (-{1over q}) 表示 (1-sqrt 5over 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\%5=±1) 的 P 都有** 5 是模 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='
    '){
        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;
    }
    
  • 相关阅读:
    Oracle存储过程小记DUAL
    线程私有数据(TSD)
    Unix 五种基本I/O模型的区别
    Redis系列(0)应用场景
    linux ubuntu引导 win7
    Redis系列(一)启动流程分析
    c++ 内存管理小结
    设计模式Facade模式应用场景
    学会理财不做穷人
    jquery 注册验证例子
  • 原文地址:https://www.cnblogs.com/Judge/p/10733929.html
Copyright © 2020-2023  润新知