数论--二次剩余 学习博客

参考学习博客:二次剩余Cipolla算法学习小记

来解析几个显然的地方:

1、证明:我们只用考虑所有x^2。如果存在不同的两个数uv,它们的平方在模意义下同余,那么显然有{\color{Red} p|(u^2-v^2)}。由平方差公式p|(u+v)(u-v)显然 {\color{Red} p} 不可能整除{\color{Red} u-v},因此p整除u+v,因此(u+v)\equiv 0(mod   p)。这个结论反过来也是成立的,因此共有\frac{p-1}{2}种互不相同的平方,显然对应了所有有解的n,而且同一个n还一定存在两个互为相反数的解。

显然1:那么显然有{\color{Red}p|(u^2-v^2) }公式  u^2\equiv v^2modp  => u^2-v^2 \equiv 0%p  =>p|(u+v)(u-v)

显然2:p不可能整除{\color{Red} (u-v)}:   \because u!=v    \because u<p && v<p    \therefore  p 不可能整除 (u-v)

令 x^2\equiv a (mod p)   对 x^2  进行定理(\frac{x^2}{p})=x^{2*(\frac{p-1}{2})}  => x^{p-1}\equiv 1 (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;
}

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/107507617