参考学习博客:二次剩余Cipolla算法学习小记
来解析几个显然的地方:
1、证明:我们只用考虑所有。如果存在不同的两个数、,它们的平方在模意义下同余,那么显然有。由平方差公式。显然 不可能整除,因此整除,因此 。这个结论反过来也是成立的,因此共有种互不相同的平方,显然对应了所有有解的,而且同一个还一定存在两个互为相反数的解。
显然1:那么显然有: 公式 %p
显然2:p不可能整除: && 不可能整除
令 (mod p) 对 进行定理 (mod p)
来看一道例题:https://ac.nowcoder.com/acm/contest/889/B
题面:
题意:
a,p已知,求x
做法: 化简:(a-b)^2=b*b-4*c%p
#include <iostream>
using namespace std;
#define LL long long
typedef long long ll;
ll w;
struct Point//x + y*sqrt(w)
{
ll x,y;
};
Point point_mul(Point a, Point b, ll p)
{
Point res;
res.x=(a.x * b.x + p) % p;
res.x=(res.x + w * a.y % p * b.y % p) % p;
res.y = a.x * b.y % p;
res.y = ( res.y + a.y * b.x % p) % p;
return res;
}
Point power(Point a, ll b, ll p)
{
Point res;
res.x = 1;
res.y = 0;
for(;b;b>>=1)
{
if (b & 1) res = point_mul(res, a, p);
a = point_mul(a, a, p);
}
return res;
}
ll powmod(ll a, ll b, ll mod)
{
ll res=1;a%=mod;
for(;b;b>>=1){
if(b&1) res=res*a%mod;
a=a*a%mod;
}
return res;
}
ll Legendre(ll a, ll p) // a^((p-1)/2)
{
return powmod(a, (p - 1) >> 1, p);
}
ll equation_solve(ll b, ll p)//求解x^2=b(%p)方程解
{
if (b == 0) return 0;
if ((Legendre(b, p) + 1) % p == 0) return -1;//表示没有解
LL a, t;
while(true)
{
a = rand() % p;
t = a * a - b;
t=(t % p + p) % p;
if ((Legendre(t, p) + 1) % p == 0) break;
}
w = t;
Point temp, res;
temp.x = a;
temp.y = 1;
res = power(temp, (p + 1) >> 1, p);
return res.x;
}
int Mod = 1e9 + 7;
ll input(){
ll x=0,f=0;char ch=getchar();
while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return f? -x:x;
}
int main() {
int T=input();
while(T--){
ll b=input(),c=input(),x,y,p=1e9+7;
ll k=((b*b%p-4*c%p)+p)%p;//右边一堆
ll tmp=equation_solve(k,p);
//tmp就是这个解,tmp*tmp=k%p
//判断是否有解
if(tmp==-1){
printf("-1 -1\n");
continue;
}
ll inv=powmod(2,Mod-2,Mod);
x=(b+tmp)%p*inv%p;
y=(b-tmp+p)%p*inv%p;
//x最小时的解
if(x>y) swap(x,y);
printf("%lld %lld\n",x,y);
}
return 0;
}