模板 - 二次剩余

又被二次剩余调教了。

以下,p是奇质数。

如果存在一个x,使得 \(x^2=n\; mod \; p\) ,则n是p的一个二次剩余。

勒让德符号: \((\frac{n}{p})\)

当n是p的二次剩余, \((\frac{n}{p})=1\)
当n不是p的二次剩余, \((\frac{n}{p})=-1\)
当p|n, \((\frac{n}{p})=0\)

结论: \((\frac{n}{p})=n^{\frac{p-1}{2}}\)

定理:定理:对于方程 \(x^2≡n\; mod \; p\) ,有 \(\frac{p-1}{2}\)​ 个不同的 n ,使得该方程有解。

所以在[0,p-1]中随机选一个数a,定义w=a^2-n,若 \((\frac{w}{p})=-1\), 那么 \((a+\sqrt{w})^{\frac{p+1}{2}}\) 就是一组二次剩余。

所以这个算法的期望复杂度只有2次。

假如n是p的二次剩余,那么n可以在模p意义下开根。

模板代码:

p是任意的奇质数。

const int p = 1e9 + 7;
struct hh {
    ll x, y;
    hh() {};
    hh(ll _x, ll _y) {
        x = _x;
        y = _y;
    }
};
ll w;
hh mul(hh a, hh b, ll p) {
    hh ans;
    ans.x = (a.x * b.x % p + a.y * b.y % p * w % p) % p;
    ans.y = (a.x * b.y % p + a.y * b.x % p) % p;
    return ans;
}
hh quick1(hh a, ll b, ll p) {
    hh ans = hh(1, 0);
    while(b) {
        if(b & 1)
            ans = mul(ans, a, p);
        a = mul(a, a, p);
        b >>= 1;
    }
    return ans;
}
ll quick2(ll a, ll b, ll p) {
    ll ans = 1;
    while(b) {
        if(b & 1)
            ans = (ans * a) % p;
        b >>= 1;
        a = (a * a) % p;
    }
    return ans;
}
ll solve(ll a, ll p) { //求解 x^2=a(mod p) 的x的值
    a %= p; //注意这句话
    if(a == 0)
        return 0;//注意这句话
    if(p == 2)
        return a;
    if(quick2(a, (p - 1) / 2, p) == p - 1)
        return -1;
    ll b, t;
    while(1) {
        b = rand() % p;
        t = b * b - a;
        w = (t % p + p) % p;
        if(quick2(w, (p - 1) / 2, p) == p - 1)
            break;
    }
    hh ans = hh(b, 1);
    ans = quick1(ans, (p + 1) / 2, p);
    return ans.x;
}

原文链接:https://blog.csdn.net/kele52he/article/details/78897187
原文链接:https://blog.csdn.net/stevensonson/article/details/85845334

posted @ 2019-08-16 15:02  韵意  阅读(499)  评论(0编辑  收藏  举报