2019牛客暑期多校训练营(第九场)B (解二次剩余方程)

二次剩余方程 q2≡a(modp):

百度词条:二次剩余
当存在某个在这里插入图片描述式子成立时,称“d是模p的二次剩余”

一.判断二次剩余方程是否有解。

欧拉准则:(判断二次剩余方程是否有解)

若是p奇质数且不能整除d,则:

d是模p的二次剩余当且仅当:在这里插入图片描述
是d模p的非二次剩余当且仅当:在这里插入图片描述

以勒让德符号表示,即为:在这里插入图片描述

二.通过已知条件和欧拉准则化简

牛客原题

已知条件:
在这里插入图片描述
易得 (x−y)2≡(x+y)2−4xy (mod p)⋯⋯⋯(1)

将条件
  在这里插入图片描述
带入上式得:

(x−y)2≡b2−4c (mod p)⋯⋯⋯(2)

首先,判断 该二次剩余方程式(2)是否由解,即判断 b2−4c 是否为模 p 的二次剩余;
设d=b2−4c;

通过欧拉准则:如果d(p-1)/2≡1 (mod p):

那么,易得 (x−y)2≡d(p+1)/2 (mod p)⋯⋯⋯(3);(d≡d⋅d(p−1)/2 (mod p))

同余式两端同时开方得:(x−y)≡d(p+1)/4 (mod p)⋯⋯⋯(4);

由条件 在这里插入图片描述 和式 (4) 可得:

在这里插入图片描述
 所以,式(5)可以解出x;(用扩展欧几里得求ax+by=c)
 那么
  由条件在这里插入图片描述可得 x+y = b or b+p;

那么,y 也就求出来了;
思路参考于https://www.cnblogs.com/violet-acmer/p/11364835.html

AC代码;

#include<bits/stdc++.h>
using namespace std;
#define ll long long
//typedef __int128 ll;
ll p=1000000007;
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 temp=y;
	y=x-(a/b)*y;
	x=temp;
	return r;
}
ll Quick_pow(ll a,ll b)//快速幂并求余 
{
	ll ans=1ll;
	while(b)
	{
		if(b&1)
		ans=ans*a%p;
		a=a*a%p;
		b>>=1; 
	}
	return ans;
}
void solve(ll b,ll c)
{
	ll d=b*b-4*c;
	d=(d+p)%p;
	if(d==0)//特判 此时x=y //这里容易坑人
	{
		printf("%lld %lld\n",b/2,b/2);//因为(x+y)mod p=b;故x=y=b/2;
		return;
	}
	if(Quick_pow(d,(p-1)/2)!=1)//欧拉准则 
	{
		printf("-1 -1\n");//无解
		return; 
	}
	ll tx,ty;
	ll D=(b%p+Quick_pow(d,(p+1)/4))%p; 
	ll gcd=exgcd(2,p,tx,ty);
	if(D%gcd!=0) return;//由贝祖公式可知无解,本题不用判
	//2x+py=gcd(2,p)的x已经求出为tx;但是我们要求的是方程2x+py=b+d^((p+1)/4) 
	//故 方程2x+py=b+d^((p+1)/4) 的解为
	//x=tx/gcd*c; 但x必须为正数
	ll g=p/gcd;
	ll x= (tx/gcd*D%g+g)%g;
	//printf("tx:%lld\n",tx);
	ll y=b-x;
	y=(y+p)%p;//保证正数
	if(x>y)
	swap(x,y);
	printf("%lld %lld\n",x,y);//x<=y 
	return;
}
int main(void)
{
	int t;
	ll b,c;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%lld %lld",&b,&c);
		solve(b,c);
	}
}

补充:
ax ≡ 1 (mod b)
可以写成
ax+by=1
运用扩展欧几里得算法,求出一组解。根据所有解的规律:
x加上b/gcd(a,b),同时y减去a/gcd(a,b)后,仍满足ax+by=c。
求出x的最小正整数解。

其实直接mod b也行的,就是有时候可能会溢出范围(这个个人觉得好理解点),所以最后mod a/gcd(a,b);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值