求解二次同余式

本文介绍了一种求解形如x^2=a(modp)的同余式的算法,其中p为奇素数。通过分解P-1并利用勒让德符号判断解的存在性,进一步求得解的具体步骤。
部署运行你感兴趣的模型镜像

求解形如 x^2 = a (mod p) 这样的同余式

/*
模P平方根:
    求 X ^2 = a (mod p)
    定理:当P为!!!奇素数 !!!的时候
    先判断(a / p )的勒让德符号, 若为-1则无解,若为1则有解
    分解P-1,然后求B,然后求出X(t-1),和a的逆元
    然后开始求 ans = ( a的逆元 * 上一个X的平方(t-k))的(t-k-1)次方对P取模
    如果  ans == -1 则 J = 1;
    如果  ans ==  1 则 J = 0;
    然后开始求现在的 X = (上一个X * B的(J*2的k次方)次方
    直到求出X0,也就是最后的解
*/
#include<bits/stdc++.h>
using namespace std;

void Divide(int p, int &t, int &s)
{
    t = 0, s= 0;
    while(p % 2 == 0)
    {
        t++;
        p /= 2;
    }
    s = p;
    return ;
}

int Pow(int a, int b, int mod)
{
    int ans = 1, base = a;
    while(b != 0)
    {
        if(b & 1)
            ans = (ans * base) % mod;
        base = (base * base) % mod;
        b >>= 1;
    }
    return ans;
}

int Legendre(int a, int p)
{
    if(a == 2)
    {
        int x = (p+1)*(p-1)/8;
        if(x % 2 == 0)
            return 1;
        else
            return -1;
    }
    else
    {
        int ans = Pow(a, (p-1)/2, p);
        if(ans == p-1)
            return -1;
        else
            return 1;
    }
}

int FindN(int p)
{
    for(int i = 1; i < p; i++)
    {
        if(Legendre(i, p) == -1)
            return i;
    }
}

int e_gcd(int a, int b, int &x, int &y)
{
    if(b == 0)
    {
        x = 1; y = 0;
        return a;
    }
    int q = e_gcd(b, a%b, y, x);
    y -= a/b*x;
    return q;
}

int Inverse(int a, int m)
{
    int x, y;
    int gcd = e_gcd(a, m, x, y);
    if(1 % gcd != 0)
        return -1;
    x *= 1/gcd;
    m = abs(m);
    int ans = x % m;
    if(ans <= 0)
        ans += m;
    return ans;
}

int JudgeJ(int A, int x, int t, int p)
{
    cout << A << " " << x << " " << t << " " << p << endl;
    x = ((x % p) * (x % p) % p);
    int xx = (A * x) % p;
    int ans = Pow(xx, pow(2, t), p);
    if(ans == p-1)
        return 1;
    else
        return 0;
}

int main()
{
    int a, p;
    printf("请输入所求算式的 a 和 p:\n");
    while( scanf("%d %d", &a, &p) != EOF)
    {
        if(Legendre(a, p) == -1)
        {
            cout << "无解" << endl;
            continue;
        }
        int t, s;
        Divide(p-1, t, s); //求t和s
        int n = FindN(p);  //找到那个不符合条件的n
        int b = Pow(n, s, p);
        int *X;
        X = (int *) malloc(sizeof(int) * (t+5));
        X[t-1] = Pow(a, (s+1)/2, p);
        t--;
        int A = Inverse(a, p);          //求A的逆元
        int k = 0;
        while(t > 0)
        {
            int j = JudgeJ(A, X[t], t-1, p);
            int B = Pow(b, j * pow(2, k), p);
            X[t-1] = ((X[t] % p) * (B % p)) % p;
            t--; k++;
        }
        printf("所求的解为:");
        cout << X[0] << endl;
    }
    return 0;
}


您可能感兴趣的与本文相关的镜像

TensorFlow-v2.9

TensorFlow-v2.9

TensorFlow

TensorFlow 是由Google Brain 团队开发的开源机器学习框架,广泛应用于深度学习研究和生产环境。 它提供了一个灵活的平台,用于构建和训练各种机器学习模型

### 二次同余方程与中国剩余定理的结合 二次同余方程的一般形式为 \( x^2 \equiv a \pmod{m} \),其中 \( m > 0 \) 且 \( a \) 是整数。此类方程通常需要先将模数分为质因数幂的形式,然后分别求解每个模数下的二次同余方程,最后利用中国剩余定理合并结果。 #### 1. 模数为质数的情况 当模数 \( m = p \)(\( p \) 为奇质数)时,二次同余方程 \( x^2 \equiv a \pmod{p} \) 的可以通过判断 \( a \) 是否为模 \( p \) 的二次剩余来确定。如果 \( a \) 是模 \( p \) 的二次剩余,则存在两个;否则无。 - 判断 \( a \) 是否为模 \( p \) 的二次剩余:计算勒让德符号 \( \left( \frac{a}{p} \right) \)。若 \( \left( \frac{a}{p} \right) = 1 \),则 \( a \) 是模 \( p \) 的二次剩余[^6]。 - 若 \( a \) 是二次剩余,可以使用 Cipolla 算法或 Tonelli-Shanks 算法求解。 #### 2. 模数为质数幂的情况 当模数 \( m = p^k \)(\( k \geq 1 \))时,二次同余方程 \( x^2 \equiv a \pmod{p^k} \) 的可以通过 Hensel 提升法从模 \( p \) 的逐步提升到模 \( p^k \) 的[^7]。 #### 3. 模数为合数的情况 当模数 \( m \) 是合数时,可以将其分为质因数幂的乘积 \( m = p_1^{k_1} p_2^{k_2} \cdots p_n^{k_n} \)。对于每个质因数幂 \( p_i^{k_i} \),分别求解二次同余方程 \( x^2 \equiv a \pmod{p_i^{k_i}} \),然后利用中国剩余定理合并这些。 以下是具体算法实现: ```python from sympy import mod_inverse, legendre_symbol, factorint def solve_quadratic_congruence(a, p): """求解二次同余方程 x^2 ≡ a (mod p),其中 p 是奇质数""" if legendre_symbol(a, p) != 1: return [] # 无 if p == 2: return [a % 2] # 使用 Tonelli-Shanks 算法求解 q = p - 1 s = 0 while q % 2 == 0: q //= 2 s += 1 if s == 1: r = pow(a, (p + 1) // 4, p) else: z = 2 while legendre_symbol(z, p) != -1: z += 1 c = pow(z, q, p) r = pow(a, (q + 1) // 2, p) t = pow(a, q, p) m = s while t != 1: i = 0 temp = t while temp != 1: temp = (temp * temp) % p i += 1 b = pow(c, 1 << (m - i - 1), p) r = (r * b) % p c = (b * b) % p t = (t * c) % p m = i return [r, p - r] def hensel_lift(r, a, p, k): """Hensel 提升法,将模 p 的提升到模 p^k 的""" for _ in range(1, k): r = (r - (r**2 - a) * mod_inverse(2 * r, p)) % (p ** (_ + 1)) return r def solve_mod_power(a, p, k): """求解二次同余方程 x^2 ≡ a (mod p^k)""" solutions = solve_quadratic_congruence(a, p) if not solutions: return [] return [hensel_lift(r, a, p, k) for r in solutions] def solve_combined(a, m): """求解二次同余方程 x^2 ≡ a (mod m),其中 m 是合数""" factors = factorint(m) solutions = [] for p, k in factors.items(): partial_solutions = solve_mod_power(a, p, k) if not partial_solutions: return [] solutions.append([(x, p**k) for x in partial_solutions]) # 使用中国剩余定理合并 def crt(solutions): x, M = solutions[0] for xi, Mi in solutions[1:]: gcd, s, t = extended_gcd(M, Mi) if (xi - x) % gcd != 0: return None temp = Mi // gcd x = (s * (xi - x) // gcd * M + x) % (M * temp) M *= temp return x % M combined_solutions = set() from itertools import product for combo in product(*solutions): res = crt(combo) if res is not None: combined_solutions.add(res) return sorted(combined_solutions) # 辅助函数 def extended_gcd(a, b): if b == 0: return a, 1, 0 gcd, x1, y1 = extended_gcd(b, a % b) x = y1 y = x1 - (a // b) * y1 return gcd, x, y ``` #### 代码说明 1. `solve_quadratic_congruence`:求解模质数 \( p \) 下的二次同余方程。 2. `hensel_lift`:通过 Hensel 提升法将模 \( p \) 的提升到模 \( p^k \) 的。 3. `solve_mod_power`:求解模 \( p^k \) 下的二次同余方程。 4. `solve_combined`:求解模合数 \( m \) 下的二次同余方程,并利用中国剩余定理合并。 #### 注意事项 - 当模数较大时,可能需要使用快速乘法以避免溢出。 - 如果模数包含因子 2,需单独处理,因为 2 不是奇质数。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值