二次剩余学习笔记
看SCOI2018的时候发现不会这个东西
来写模板与简单证明
p是奇质数,偶的就那一个,就不讨论了
二次剩余
求解(x^2equiv n pmod p)
勒让德符号
(a^frac{P-1}{2}equiv left(frac{a}{p} ight) pmod p)
令(x^2equiv a pmod p)
存在x时(x^{p-1}equiv 1 pmod p)
所以(xequiv a^{frac{1}{2}}pmod p),(x^{p-1}equiv a^{frac{p-1}{2}}equiv 1pmod 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}
ot equiv 1pmod 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^2pmod 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
",max(x0,mod-x0));
}
int main(){
int T=read();
while(T--){
n=read(),mod=read();
if(n==0){
printf("%d
",0);continue;
}
if(!check(n)) printf("Hola!
");
else solve();
}
return 0;
}