二次剩余学习笔记
注意,下面的运算都是在模意义下进行的。
给定 \(n\),求 \(x^2\equiv n\)
\(x\) 存在条件为 \(n^{\frac {p-1}2}=1\),证明用费马小定理,略。
如何求出 \(x\),随机一个 不存在 二次剩余的值 \(a^2-n\),设为 \(w^2\)
这里可以把 \(w\) 理解为一个虚数。由于 \(w^2\) 不存在二次剩余,所以
\[w^p=w^{p-1}\times w=(w^2)^{\frac {p-1}2}\times w=(a^2-
n)^{\frac{p-1}2}\times w=(-1)\times w=-w\]
那么 \((a+w)^{p+1}=(a_p+w_p)(a+w)=(a-w)(a+w)=a^2-w^2=n\)
我们要求 \((a+w)^{\frac{p+1}2}\),可以扩域计算。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int read()
{
int s=0;
char ch=getchar();
while(ch>'9'||ch<'0')
ch=getchar();
while(ch>='0'&&ch<='9')
s=s*10+ch-48,ch=getchar();
return s;
}
int pown(int x,int y,int p)
{
if(!y)
return 1;
int t=pown(x,y>>1,p);
if(y&1)
return 1LL*t*t%p*x%p;
return 1LL*t*t%p;
}
mt19937 gen(time(0));
int t,n,p,a,k;
struct node{
LL x,y;
node operator*(const node&n)const{
return (node){(x*n.x+y*n.y%p*k)%p,(y*n.x+x*n.y)%p};
}
};
node pown(node x,int y)
{
if(!y)
return (node){1,0};
node t=pown(x,y>>1);
if(y&1)
return t*t*x;
return t*t;
}
int main()
{
t=read();
while(t--)
{
n=read(),p=read();
if(!n)
{
puts("0");
continue;
}
if(pown(n,p-1>>1,p)^1)
puts("Hola!");
else
{
while(1)
{
a=gen()%p,k=(1LL*a*a%p+p-n)%p;
if(pown(k,p-1>>1,p)==1)
continue;
int g=pown((node){a,1},p+1>>1).x;
if(p-g<g)
printf("%d %d\n",p-g,g);
else
printf("%d %d\n",g,p-g);
break;
}
}
}
}

浙公网安备 33010602011771号