【模板】二次剩余Cipolla算法/欧拉准则-bzoj5104: Fib数列

版权声明:欢迎转载(请附带原链接)ヾ(๑╹◡╹)ノ" https://blog.csdn.net/corsica6/article/details/85051417

欧拉准则

对于质数 p p x 2 a ( m o d p ) a p 1 2 1 ( m o d p ) x^2\equiv a\pmod p\Leftrightarrow a^{\frac{p-1}{2}}\equiv 1\pmod p

证明:

充分性:
a p 1 2 = ( x 2 ) p 1 2 = x p 1 1 ( m o d p ) a^{\frac{p-1}{2}}=(x^2)^{\frac{p-1}{2}}=x^{p-1}\equiv 1\pmod p

必要性:
g g 为模 p p 意义下的原根, g i a ( m o d p ) g^i\equiv a\pmod p ,则
g i ( p 1 ) 2 1 ( m o d p ) g^{\frac{i(p-1)}{2}}\equiv 1\pmod p
g g 为原根,则 ( p 1 ) i ( p 1 ) 2 (p-1)|\frac{i(p-1)}{2} i i 为偶数, x g i 2 ( m o d p ) x\equiv g^{\frac i2}\pmod p


Cipolla算法

一种求解模奇质数意义下的二次同余方程的算法。

p p 为奇质数,给定 a a ,求 x x 满足: x 2 a ( m o d p ) x^2\equiv a\pmod p

复杂度 O ( log p ) O(\log p)

具体算法:

可能需要死记硬背一下。。。

随机找到任意一个 b b ,满足 b 2 a w b^2-a\equiv w w w 是模 p p 意义下的非二次剩余( w p 1 2 1 ( m o d p ) w^{\frac{p-1}{2} }\equiv -1\pmod p )。

类似于虚数,设 i = w i= \sqrt w ,扩域后每个数表达为 ( a , b ) = a + b i (a,b)=a+bi ,运算为:
( r 1 , d 1 ) + ( r 2 , d 2 ) = ( r 1 + r 2 , d 1 + d 2 ) (r_1,d_1)+(r_2,d_2)=(r_1+r_2,d_1+d_2)
( r 1 , d 1 ) ( r 2 , d 2 ) = ( r 1 r 2 + d 1 d 2 w , r 1 d 2 + r 2 d 1 ) (r_1,d_1)·(r_2,d_2)=(r_1 r_2+d_1d_2w,r_1d_2+r_2d_1)

< G , + , > <G,+,·> 是个环,满足交换律和结合律。

答案即为: x = ( b + i ) p + 1 2 x=(b+i)^{\frac {p+1}{2}}

证明:
x 2 \quad x^2
= ( b + i ) p ( b + i ) =(b+i)^p(b+i)
= ( b p + i p ) ( b + i ) =(b^p+i^p)(b+i) ( ( b + i ) p (b+i)^p 二项式定理展开后其余项均含 p p 模后为0)
b p b , i p = w p 1 2 i = i b^p\equiv b,i^p=w^{\frac{p-1}{2}}i=-i
x 2 = ( b i ) ( b + i ) = b 2 i 2 = b 2 w = a x^2=(b-i)(b+i)=b^2-i^2=b^2-w=a


例题

传送门:bzoj5104

求在 ( m o d 1 0 9 + 9 ) \pmod{10^9+9} 的意义下,数字 N N F i b Fib 数列中出现在哪个位置
无解输出 1 -1
N < = 1 0 9 + 9 N < = 10^9+9


题解

F i b Fib 数列的通项公式: F n = ( 1 + 5 2 ) n ( 1 5 2 ) n 5 F_n=\frac{(\frac{1+\sqrt 5}{2})^n-(\frac{1-\sqrt 5}{2})^n}{\sqrt 5}

吐槽一下这怎么记得到啊。。。

t = ( 1 + 5 2 ) n , T = 5 N t=(\frac{1+\sqrt 5}{2})^n,T=\sqrt 5N

t ( 1 ) n 1 t = T t-(-1)^n\frac{1}{t}=T

左右同乘 T T

得到方程 t 2 T t ( 1 ) n = 0 t^{2}-Tt-(-1)^n=0

n n 的奇偶讨论,先求出 Δ \sqrt\Delta B S G S BSGS 求解。


代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+9,qrt5=383008016,nv2=500000005,blk=sqrt(mod)+1,bs=691504013;
int n,ans,ca,cb;
map<int,int>mp[2];

inline int fp(int x,int y)
{
	int re=1;
	for(;y;y>>=1,x=(ll)x*x%mod)
	  if(y&1) re=(ll)re*x%mod;
	return re;
}

inline int ad(int x,int y){x+=y;return x>=mod?x-mod:x;}
inline int dc(int x,int y){x-=y;return x<0?x+mod:x;}

namespace sc_surplus{
    int w,a,b;
    
    struct cc{
    	int r,i;
    	cc(int r,int i):r(r),i(i){};
    	cc operator *(const cc&ky)const
		{return cc(ad((ll)r*ky.r%mod,(ll)i*ky.i%mod*(ll)w%mod),ad((ll)r*ky.i%mod,(ll)i*ky.r%mod));}
        cc operator *=(const cc&ky){return (*this)=(*this)*ky;}
	};
    
    inline int fp(cc x,int y)
    {
    	cc re=cc(1,0);
    	for(;y;y>>=1,x*=x) if(y&1) re*=x;
    	return re.r;
    }
    
    inline bool ck(int x)
    {return (::fp((w=dc((ll)x*x%mod,a)),(mod-1)/2)==mod-1);}
    
	inline int fd_sqrt(int x)
	{
		if(::fp(x,(mod-1)/2)!=1) return 0;
		a=x;for(b=rand();!ck(b);b=rand());
		return fp(cc(b,1),(mod+1)/2);
	}	
}

inline void cal(int od)
{
	int i,j,a=ca,b=cb,pw;
	for(i=0;i<2;++i) if(!mp[i].empty()) mp[i].clear();
	for(i=0;i<blk;++i){
		j=i&1;
		if(mp[j].find(a)==mp[j].end()) mp[j][a]=i;
		if(mp[j].find(b)==mp[j].end()) mp[j][b]=i;
		a=(ll)a*bs%mod;b=(ll)b*bs%mod;
	}
	pw=fp(bs,blk);int vl=pw,re=blk;
	for(i=0;i<=blk;++i){
		j=-1;
		if(od){
		   if((re&1)&&(mp[0].find(vl)!=mp[0].end())) j=mp[0][vl];
		   else if((!(re&1))&&(mp[1].find(vl)!=mp[1].end())) j=mp[1][vl];
		}else{
		   if((re&1)&&(mp[1].find(vl)!=mp[1].end())) j=mp[1][vl];
		   else if((!(re&1))&&(mp[0].find(vl)!=mp[0].end())) j=mp[0][vl];
		}if(~j) {re-=j;ans=min(ans,re);return;}
		vl=(ll)vl*pw%mod;re+=blk;
	}
}

int main(){
	srand(time(0));
	scanf("%d",&n);ans=mod+10;
	if(n==1) {puts("1");return 0;}
	int i,j,x,y;
	n=(ll)n*qrt5%mod;
	if((x=sc_surplus::fd_sqrt(((ll)n*n+4)%mod))){
		ca=(ll)ad(n,x)*nv2%mod;cb=(ll)dc(n,x)*nv2%mod;cal(0);
	}
	if((x=sc_surplus::fd_sqrt(((ll)n*n-4+mod)%mod))){
		ca=(ll)ad(n,x)*nv2%mod;cb=(ll)dc(n,x)*nv2%mod;cal(1);
	}
	printf("%d",ans==mod+10?(-1):ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/85051417
fib