二次剩余学习笔记

注意,下面的运算都是在模意义下进行的。

给定 \(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;
			}
		}
	}
}
posted @ 2023-08-06 20:44  灰鲭鲨  阅读(13)  评论(0)    收藏  举报