模素数幂的二次同余方程的程序C语言,二次同余方程的解

今天要讨论的问题是解方程

6b5044e5c8c6549a2375fcc96d55a3b5.png,其中

b7c07b0343c61b787991bdbf6d4c74ce.png是奇质数。

引理:

cc88e22256989779d640d6318c78754c.png

证明:由费马小定理,

9efde5f10b2d1255f1a975db9c66ad0c.png

引理:方程有解当且仅当

f08789285a6af69e8656dc76eb04ef81.png

定理:设

4592a95b29f3780ef360ae9079c2d63d.png满足

9659763b362b7da8f8f831c8416ffe92.png不是模

b7c07b0343c61b787991bdbf6d4c74ce.png的二次剩余,即

568d7cf4d91ba13c8d7a2b8b37fafeba.png无解,那么

04c9043e699990128080160f682668ff.png是二次

剩余方程6b5044e5c8c6549a2375fcc96d55a3b5.png的解。

证明:由

66a3fca98c021646cebcaa6e8e8456ba.png,前面的等号用二项式定理和

5c8fdcbbf6745765ab625f85fe585d47.png,后面的等

号用了费马小定理和

34609e1df1d06f7f5a3352336943ddba.png是模

b7c07b0343c61b787991bdbf6d4c74ce.png的二次非剩余。然后

29474acb774eadf6970734a4e19a4b4d.png

在算法实现的时候,对

6f8166f3c337b327cf4c4a256a92591f.png的选择可以随机,因为大约有一半数是模

b7c07b0343c61b787991bdbf6d4c74ce.png的二次非剩余,然后快速幂即可。

题意:求二次同余方程的解。

代码:

#include

#include

#include

#include

#include

#include

using namespace std;

typedef long long LL;

LL quick_mod(LL a, LL b, LL m)

{

LL ans = 1;

a %= m;

while(b)

{

if(b & 1)

{

ans = ans * a % m;

b--;

}

b >>= 1;

a = a * a % m;

}

return ans;

}

struct T

{

LL p, d;

};

LL w;

//二次域乘法

T multi_er(T a, T b, LL m)

{

T ans;

ans.p = (a.p * b.p % m + a.d * b.d % m * w % m) % m;

ans.d = (a.p * b.d % m + a.d * b.p % m) % m;

return ans;

}

//二次域上快速幂

T power(T a, LL b, LL m)

{

T ans;

ans.p = 1;

ans.d = 0;

while(b)

{

if(b & 1)

{

ans = multi_er(ans, a, m);

b--;

}

b >>= 1;

a = multi_er(a, a, m);

}

return ans;

}

//求勒让德符号

LL Legendre(LL a, LL p)

{

return quick_mod(a, (p-1)>>1, p);

}

LL mod(LL a, LL m)

{

a %= m;

if(a < 0) a += m;

return a;

}

LL Solve(LL n,LL p)

{

if(p == 2) return 1;

if (Legendre(n, p) + 1 == p)

return -1;

LL a = -1, t;

while(true)

{

a = rand() % p;

t = a * a - n;

w = mod(t, p);

if(Legendre(w, p) + 1 == p) break;

}

T tmp;

tmp.p = a;

tmp.d = 1;

T ans = power(tmp, (p + 1)>>1, p);

return ans.p;

}

int main()

{

int t;

scanf("%d", &t);

while(t--)

{

int n, p;

scanf("%d %d",&n,&p);

n %= p;

int a = Solve(n, p);

if(a == -1)

{

puts("No root");

continue;

}

int b = p - a;

if(a > b) swap(a, b);

if(a == b)

printf("%d\n",a);

else

printf("%d %d\n",a,b);

}

return 0;

}

接下来我们来解另一个二次同余方程

e2a57fcf9a238af016e9440c22155be8.png的解,其中

b123b0802e51943f3d2e833e53749186.png,并且

17a50a084f0085af8cf8d145b0b60fbd.png是奇质数。方法如下

先求出方程

012ecda6a885ab08bd123ba00b92d245.png的一个解

a0cb572452c876bda85a6c14b9b4fd16.png,那么进一步有

01b585a860258b021b33abcdbb0464fc.png

我们知道

f896821d3b5e9645c57faba85120c51f.png

那么也就是说

b83dce3d1357a2ef9398edd1e7b61944.png

可以证明

6627776d3ff3617d61c8190d0bedc436.png

ab4245634dead6829f99151a7f5c1a1e.png,那么最终得到

877545ecdbef71596819f7a20a146851.png

这里由于

8da48aa89d291ae7f55f9df1204d66de.png不是素数,所以求逆元用扩展欧几里得算法即可。

例如:求方程

a7b00c2ae70dfab5667a31fdb81d2e71.png的解

分析:利用上述方法求得

c73c5042152669cda78cf8a87b74a9e7.png,最终解得

f74b2c76d19388d0969d7029b7b6643b.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值