2019牛客多校第九场B-Quadratic equation(二次剩余模板题)

题目链接

简单讲下二次剩余,详细讲解可以找篇博客,判断是否有解核心是利用费马小定理,然后构造平方差公式

a^{p-1}-1\equiv 0(mod p)转化成(a^{\frac{p-1}{2}}+1)*(a^{\frac{p-1}{2}}-1)

 

二次剩余做得少,临时搬了个板子(这板子还是有时会RE),没想到这板子少了一句话然后一直莫名WA

我们只要化简成X^2%mod=c就可以套模板了,观察到

①^2-4*②得到下列式子:

((x-y)^{2})\%mod = (b\times b-4\times c)\%mod

解出来x-y再与x+y联立即可,注意在同余方程下除法要用逆元计算即可。

#include <iostream> 
#include<bits/stdc++.h>  
#include <ctime>
using namespace std;
typedef long long LL;
typedef long long ll;
#define random(a,b) (rand()%(b-a+1)+a)
LL quick_mod(LL a, LL b, LL c) { LL ans = 1; while (b) { if (b % 2 == 1)ans = (ans*a) % c; b /= 2; a = (a*a) % c; }return ans; }
 
LL p=1e9+7;
LL w;//二次域的D值
bool ok;//是否有解
 
struct QuadraticField//二次域
{
	LL x, y;
	QuadraticField operator*(QuadraticField T)//二次域乘法重载
	{
		QuadraticField ans;
		ans.x = (this->x*T.x%p + this->y*T.y%p*w%p) % p;
		ans.y = (this->x*T.y%p + this->y*T.x%p) % p;
		return ans;
	}
	QuadraticField operator^(LL b)//二次域快速幂
	{
		QuadraticField ans;
		QuadraticField a = *this;
		ans.x = 1;
		ans.y = 0;
		while (b)
		{
			if (b & 1)
			{
				ans = ans*a;
				b--;
			}
			b /= 2;
			a = a*a;
		}
		return ans;
	}
};
 
 ll exgcd(ll a,ll b,ll &x,ll &y)//扩展欧几里得
{
	if(b==0)
	{
		x=1;    
		y=0;
		return a;
	}
	ll r=exgcd(b,a%b,x,y);
	ll t = x - a / b * y; x = y; y = t; 
	return r;
	
}

LL Legender(LL a)//求勒让德符号
{
	LL ans=quick_mod(a, (p - 1) / 2, p);
	if (ans + 1 == p)//如果ans的值为-1,%p之后会变成p-1。
		return -1;
	else
		return ans;
}
 
LL Getw(LL n, LL a)//根据随机出来a的值确定对应w的值
{
	return ((a*a - n) % p + p) % p;//防爆处理
}
 
LL Solve(LL n)
{
	LL a;
	if(n==0)return 0;//当时复制板子漏了一句话。。崩了 
	if (p == 2)//当p为2的时候,n只会是0或1,然后0和1就是对应的解
		return n;
	if (Legender(n) == -1)//无解
		ok = false;
	srand((unsigned)time(NULL));
	while (1)//随机a的值直到有解
	{
		a = random(0, p - 1);
		w = Getw(n, a);
		if (Legender(w) == -1)
			break;
	}
	QuadraticField ans,res;
	res.x = a;
	res.y = 1;//res的值就是a+根号w
	ans = res ^ ((p + 1) / 2);
	return ans.x;
}
 
int main()
{
	LL b,c,n,k,ans1,ans2;
    LL inv=quick_mod(2,p-2,p) ;
	int T;
	cin>>T;

	while (T--)
	{
		scanf("%lld%lld",&b,&c);
		ll n=(b*b%p-4*c%p+p)%p;

		ok = true;
		n %= p;
		ans1 = Solve(n);
		ans2 = p - ans1;//一组解的和是p
		if (!ok)
		{
			
			printf("-1 -1\n");

		}
		else{
			ll x=(ans1+b)%p*inv%p;
		    ll  y=(b-x+p)%p;
          cout<<min(x,y)<<" "<<max(x,y)<<endl;
            
		}
		//如果多组解看下面 
	//	if (ans1 == ans2)
		//	printf("%lld\n", ans1);
	//	else
		//	printf("%lld %lld\n", ans1, ans2);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值