二次剩余的介绍

我们定义n==x*xmod p 中如果有非零解称n为p的二次剩余,不过并非所有数都有二次剩余,在此我们只讨论p为奇素数的情况,我们引用l勒让德符号,(a/p)={1,有二次剩余,0,amodp==0,-1,无二次剩余}。

那么如何求解二次剩余的解呢,我们有欧拉准则(a/p)=a的(p-1)/2次这个证明很简单,费马小定理可以看出。

我们使用Cipolla算法去解p的二次剩余

先找到a满足(a*a-n)的(p-1)/2次满足二次非剩余,然后定义i*i=a*a-n,代入即n=(a+i)的(p+1)/2次。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<set>
#include<string.h>
#include<vector>
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
#define int long long 
int qpow(int a,int b,int p){
	int ans=1;
	a%=p;
    while(b){
		if(b&1)ans=ans*a%p;
		a=a*a%p;
		b>>=1; 
	}
	return ans;
}
int mod(int a,int p){
	return (a%p+p)%p;
}
namesapce Qresidue
int legendre(int a,int p){
	return qpow(mod(a,p),(p-1)/2,p);
}
int find_a(int n,int p){
	for(int a=0;a<p;++a){
		if(lengendre(a*a-n,p)==p-1)return a;
	}
	return -1;
}
struct expnum{
	int a,b;
};
int a,p,n;
expnum mul(expnum i1,expnum i2){
	int c=a*a-n;
	return {(i1.a*i2.a+i1.b*i2.b%p*c)%p,(i1.a*i2.b+i1.b*i2.a)%p};
}
expnum qpow(expnum a,int n){
	expnum ans{1,0};
	while(n){
		if(n&1)ans=mul(ans,a);
		a=mul(a,a);
		n>>=1;
	}
	return ans;
}
int cul(int n,int p){
	if(n%p==0)return 0;
	if(legendre(n,p)!=1)return -1;
	Qresidue::n=n,Qresidue::p=p;
	a=find_a(n,p);
	return mod(qpow(expnum{a,1},(p+1)/2).a,p)); 
}
int main(){
	cin>>a>>p;
	cout<<cul(a,p)<<endl;
	return 0; 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值