二次剩余(懒人模板总结)

Posted chasedeath

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二次剩余(懒人模板总结)相关的知识,希望对你有一定的参考价值。

二次剩余(懒人模板总结)

只考虑奇质数的情况

设求(sqrt a pmod P)

Part1 判断

存在二次剩余即(a^{frac{(P-1)}{2}}=1 pmod P)


(对于所有(a=0,1)的情况需要特判)

Part2 原根法求二次剩余

先求出(P)的一个原根(g)

那么可以用(g^k)表示出([1,P-1])的所有数

(BSGS)可以在(O(sqrt nlog n))的时间内求出(a=g^k)

如果存在原根,那么(kmod 2=0)

答案就是(g^{frac{k}{2}}mod P)

int Quad(int a,int k=0) {
	if(a<=1) return a;    
    int g=Getg(P);
	static map <int,int> M;
	int S=sqrt(P-1);
	for(int i=0,t=1;i<S;++i,t=1ll*t*g%P) M[t]=i;
	int res=0;
	int w=qpow(g,S);
	for(int i=0,t=1;i<P-1;i+=S,t=1ll*t*w%P) {
		ll x=1ll*a*qpow(t,P-2)%P;
		if(M.count(x)) {
			res=M[x]+i;
			break;
		}
	}
	res=qpow(g,res/2);
	if(k) res=min(res,(P-res)%P);
	return res;
}

Part3 更快的方法

要先找到一个数(x),满足不存在(sqrt{x^2-a}pmod P)

可以随机(x),期望可以在(O(1))时间内找到这样的(x)

然后构造复数((alpha,eta)=alpha+sqrt{x^2-a}eta)

求出((x,1)^{frac{(P+1)}{2}}),模拟复数乘法即可

可以证明结果没有虚部,就是答案

int Quad(int a,int k=0) {
	if(a<=1) return a;
	int x;
	while(1) {
		x=1ll*rand()*rand()%P;
		ll res=qpow((1ll*x*x-a+P)%P,(P-1)/2);
		if(res!=1) break;
	}
	ll w=(1ll*x*x-a+P)%P;
	int d=(P+1)/2;
	ll resx=1,resy=0;
	ll xx=x,yy=1;
	while(d) {
		if(d&1) {
			ll tx=(resx*xx+resy*yy%P*w)%P,ty=(resx*yy+resy*xx)%P;
			resx=tx,resy=ty;
            // 模拟复数乘法
		}
		ll tx=(xx*xx+yy*yy%P*w)%P,ty=2*xx*yy%P;
		xx=tx,yy=ty;
        // 模拟复数乘法
		d>>=1;
	}
	x=resx; // 答案就是实部
	if(k) x=min(x,(P-x)%P);
	return x;
}


以上是关于二次剩余(懒人模板总结)的主要内容,如果未能解决你的问题,请参考以下文章

[模板]二次剩余(无讲解)

java总结第二次(剩余内容)//类和对象1

C++模板初阶--懒人创造世界

C++模板初阶--懒人创造世界

C++模板初阶--懒人创造世界

C++模板初阶--懒人创造世界