【二次剩余】【模板】

二次剩余


俗称膜意义下开根
证明等一系列看懂了,但之后还是不会退,所以背板吧QAQ

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int mod;
int add(int a,int b) {return a+b>=mod?a+b-mod:a+b;}
int del(int a,int b) {return a<b?a+mod-b:a-b;}
int mul(int a,int b) {return 1ll*a*b%mod;}
int quick_mul(int a,int k,int ans=1){for(;k;k>>=1,a=mul(a,a))if(k&1)ans=mul(ans,a);return ans;}
int w;
struct nd{
	int x,y;
	nd(){}
	nd(int a,int b){x=a;y=b;}
	nd operator*(const nd &a)const{return nd(add(mul(x,a.x),mul(mul(y,a.y),w)),add(mul(x,a.y),mul(y,a.x)));}
};
nd quick_mul(nd a,int k,nd ans=nd(1,0)){for(;k;k>>=1,a=a*a)if(k&1)ans=ans*a;return ans;}
bool check_sqrt(int a){return quick_mul(a,(mod-1)/2)==1;}
int get_w(int n)
{
	for(int a=rand();;a=rand())
		if(!check_sqrt(del(mul(a,a),n)))
			return w=del(mul(a,a),n),a;
}
void get_sqrt(int n,int &x1,int &x2)
{
	int a=get_w(n);
	x1=(quick_mul(nd(a,1),(mod+1)/2)).x;
	x2=mod-x1;
}
int n;
int main()
{
	srand(time(0));
	int x1,x2,T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&mod);
		if(!n){printf("0\n");continue;}
		if(!check_sqrt(n)){printf("Hola!\n");continue;}
		get_sqrt(n,x1,x2);
		if(x1>x2)swap(x1,x2);
		if(x1!=x2)printf("%d %d\n",x1,x2);
		else	  printf("%d\n",x1);
	}

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值