Secondary residue (Jane: no proof)

The use of quadratic remainder is
a bit like an inverse element. When solving the problem, there should be no decimals in
x2≡n(modp)
the modulus. All that is needed is this x. The following is the case where p is a prime number.

Theorem
1. There are a total of (p-1)/2+1 kinds of n to make the equation have a solution.
2
Insert picture description here
3. Insert picture description here
Solving code

#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<map>
#include<stack>
#include<vector>
#include<iomanip>
#include<algorithm>
#include<unordered_map>
#include<string>
#include<cmath>
#include<cstdio>
#include<fstream>
#include<time.h>
#define lson rt<<1
#define rson rt<<1|1
#define fmid (tree[rt].l + tree[rt].r) / 2

using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
const ll mod = 1e9 + 9;
const double eps = 1e-6;
const double PI = acos(-1);
#define MOD(a, b) a >= b ? a % b + b : a
#define random(a,b) (rand()%(b-a+1)+a)
void acc_ios()
{
    
    
    ios::sync_with_stdio(false);
    cin.tie(0);
}

ll w;
bool ok;
struct QuadraticField
{
    
    
    ll x, y;
    QuadraticField operator*(QuadraticField T)
    {
    
    
        QuadraticField ans;
        ans.x = (this->x * T.x % mod + this->y * T.y % mod * w % mod) % mod;
        ans.y = (this->x * T.y % mod + this->y * T.x % mod) % mod;
        return ans;
    }
    QuadraticField operator^(ll b)
    {
    
    
        QuadraticField ans;
        QuadraticField a = *this;
        ans.x = 1;
        ans.y = 0;
        while(b)
        {
    
    
            if(b & 1)
            {
    
    
                ans = ans * a;
                b--;
            }
            b /= 2;
            a = a * a;
        }
        return ans;
    }
};


ll fast_pow(ll a, ll b)
{
    
    
    ll res = 1;
    while(b)
    {
    
    
        if(b & 1) res = (res * a) % mod;
        a = (a * a) % mod;
        b >>= 1;
    }
    return res;
}

ll legender(ll a)
{
    
    
    ll ans = fast_pow(a, (mod - 1) / 2);
    if(ans + 1 == mod)
        return -1;
    else
        return ans;
}

ll getW(ll n, ll a)
{
    
    
    return ((a * a - n) % mod + mod) % mod;
}

ll solve(ll n)
{
    
    
    ll a;
    if(mod == 2)
        return n;
    if(legender(n) == -1)
        ok = false;
    srand((unsigned)time(NULL));
    while(1)
    {
    
    
        a = random(0, mod - 1);
        w = getW(n, a);
        if(legender(w) == -1)
            break;
    }
    QuadraticField ans, res;
    res.x = a;
    res.y = 1;
    ans = res^((mod + 1) / 2);
    return ans.x;
}

ll comp(ll a, ll b)
{
    
    
    if(a < b) return 0;
    if(a == b) return 1;
    if(b > a - b) b = a - b;
    ll ans = 1, ca = 1, cb = 1;
    for(int i = 0; i < b; i++)
    {
    
    
        ca = ca * (a - i) % mod;
        cb = cb * (b - i) % mod;
    }
    ans = ca * fast_pow(cb, mod - 2) % mod;
    return ans;
}


int main()
{
    
    
    acc_ios();
    ll n, ans1, ans2;
    cin>>n;
    ok = true;
    n %= mod;
    ans1 = solve(n);
    ans2 = mod - ans1;
    if(!ok)
    {
    
    
        cout<<"no root"<<endl;
        return 0;
    }
    if(ans1 == ans2)
        cout<<ans1<<endl;
    else
        cout<<ans1<<" "<<ans2<<endl;
    return 0;
}


Guess you like

Origin blog.csdn.net/weixin_43891021/article/details/107522209