二次剩余(模板)

二次剩余

存在 \(x^2\ \%\ p = n\), 如果存在这样的\(x\)那么,认为\(( \dfrac{n}{p})\) 有解。

  • \((\dfrac{n}{p}) = 1\): n在模p意义下是二次剩余

  • \((\dfrac{n}{p}) = -1\):a在模p意义下是非二次剩余

  • \((\dfrac{n}{p}) = 0\)\(n\ \% \ p = 0\)

\(p\)是一个奇素数 , \((\dfrac{n}{p}) = n^ {\frac{p-1}{2} }\)

步骤

因为有解的情况下, 大约有\(\dfrac{p-1}{2}\)\(a\)满足条件,大约随机数算出的期望是\(2\), 所以就可以放心的随机数了

  • \(a = rand() \% p\)
  • \(w = a*a - n\)
  • \((\dfrac{w}{p}) = w^ {\frac{p-1}{2} }= -1\)\(x = (a +\sqrt{w})^{\frac{p+1}{2}}\)\((\dfrac{n}{p})\)的解

因为要计算\((a +\sqrt{w})^{\frac{p+1}{2}}\), 可以把\((a +\sqrt{w})^{\frac{p+1}{2}}\)看成两部分来乘(类似于虚数乘法,把\(\sqrt{w}\)看成\(i\))

代码

ll w;
struct Num{ 
    ll x, y;
    Num(){
        x = y = 0;
    }
    Num(ll xx, ll yy){
        x = xx;
        y = yy;
    }
    Num operator * (Num const & a)const{
        Num ans;
        ans.x = ((x * a.x)%p + (y * a.y)%p * w %p + p)%p;
        ans.y = ((x * a.y)%p + (y * a.x)%p + p)%p;
        return ans;
    }
};

ll pow_num(Num a, ll b){    
    Num ans = {1, 0};
    while(b){
        if(b&1)
            ans = ans*a;
        a = a*a;
        b /= 2;
    }
    return ans.x%p;
}

ll pow(ll a, ll b){
    ll ans = 1;
    while(b){
        if(b&1)
            ans = ans*a%p;
        a = a*a%p;
        b /= 2;
    }
    return ans;
}

ll check(ll n){
    ll ans = pow(n, (p-1)/2);
    if(ans == p-1)
        return -1;
    else
        return 1;
}

ll solve(ll n){
    n %= p;
    if(check(n) == -1)  \\如果当前的check(n) == -1那么就不存在解,返回-1
        return -1;
    if(p == 2) return n;    \\p = 2的时候, n = 0,1。那么x = n
    ll a;
    srand(time(NULL));
    while(1){
        a = rand()*13331%p;     \\随机数一个a
        w = ((a*a%p - n)%p + p)%p;  
        if(check(w) == -1)
            break;
    }
    Num ans = {a, 1};
    return pow_num(ans, (p+1)/2);
}

猜你喜欢

转载自www.cnblogs.com/zhuyou/p/11364593.html