二次剩余学习笔记

二次剩余学习笔记

看SCOI2018的时候发现不会这个东西
来写模板与简单证明
p是奇质数,偶的就那一个,就不讨论了

二次剩余

求解\(x^2\equiv n \pmod p\)

勒让德符号

\(a^\frac{P-1}{2}\equiv \left(\frac{a}{p}\right) \pmod p\)

\(x^2\equiv a \pmod p\)
存在x时\(x^{p-1}\equiv 1 \pmod p\)
所以\(x\equiv a^{\frac{1}{2}}\pmod p\)\(x^{p-1}\equiv a^{\frac{p-1}{2}}\equiv 1\pmod p\)

不存在x时\(a^{\frac{p-1}{2}}\)不能被表示成\(x^{p-1}\) ,于是这个东西就不等于1,又因为它的平方等于1,所以它就等于-1(膜意义下)

cipolla算法

首先随机a使得\(a^2-n\)不是二次剩余
\(\omega =\sqrt{a^2-n}\),作为当前数域下单位根
由于满足一系列性质,这个数域是成立的

又因为\(\omega^2\)不是二次剩余,由勒让德符号可知\((w^2)^{\frac{p-1}{2}}\equiv w^{p-1}\not \equiv 1\pmod p\)
由费马小定理,\((w^2)^{p-1}\equiv 1 \pmod p\)
所以\(w^{p-1}\equiv -1\)

于是就可以搞事情了

有这样一个式子

\[(a+w)^{p+1} \]

\[\equiv(a+w)^p(a+w) \]

\[\equiv(\sum_i a^iw^{p-i}C^i_p)(a+w) \pmod p \]

因为\(i!=p,0\)时组合数的阶乘p无法消掉(奇质数),所以\(mod~p\)之后为0

\[\equiv (a^p+w^p)(a+w) \pmod p \]

由上面的结论和费马小定理:

\(w^{p-1}\equiv -1\)
\(a^{p-1}\equiv 1\)

\[\equiv (a-w)(a+w) \pmod p \]

\[\equiv a^2-w^2\pmod p \]

\[\equiv a^2-(a^2-n)\pmod p \]

\[\equiv n \pmod p \]

整理得到

\[(x^2)\equiv (a+w)^{\frac{p+1}{2}*2}\equiv (a+w)^{p+1}\equiv n \pmod p \]

\(x \equiv \pm (a+w)^{\frac{p+1}{2}}\)

可以证明其不含\(w\)

代码实现

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#define ll long long 
using namespace std;
ll read(){
	ll x=0,pos=1;char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
	return pos?x:-x; 
}
ll mod,n;
ll i2;
struct complex{
	ll r,i;
	complex(ll r=0,ll i=0):r(r),i(i){}
	int operator == (complex y){
		return r==y.r&&i==y.i;
	}
	complex operator *(complex y){
		return complex((r*y.r%mod+i*y.i%mod*i2%mod)%mod,((r*y.i%mod+i*y.r)%mod)%mod); 
	}
}; 
complex ksm(complex a,int b){
	complex res=complex(1,0);
	while(b){
		if(b&1) res=res*a;
		a=a*a;
		b>>=1;
	}
	return res;
}
int check(int x){
	return ksm(complex(x,0),(mod-1)/2)==1;
}
int R(int now){
	return ((rand()<<15)+rand())%(now-1)+1;
} 
void solve(){
	ll a=R(mod);
	while(check((a*a+mod-n)%mod)) a=R(mod);
	i2=(a*a%mod-n+mod)%mod;
	ll x0=ksm(complex(a,1),(mod+1)/2).r;
	printf("%lld ",min(x0,mod-x0));
	printf("%lld\n",max(x0,mod-x0)); 
}
int main(){
	int T=read();
	while(T--){
		n=read(),mod=read();
		if(n==0){
			printf("%d\n",0);continue;
		}
		if(!check(n)) printf("Hola!\n");
		else solve();
	}
	return 0;
} 
posted @ 2019-12-17 17:02  lcyfrog  阅读(313)  评论(0编辑  收藏  举报