演算法原理請wiki:tonelli–shanks algorithm,迅速深入理解是不太可能的,與cipola演算法相比,shanks解法更數論一點。
(這個演算法是正常的,但是還是tle)
大概流程是: r2
≡nmodp
r 2≡
nmod
p令p−
1=q2
s p−1
=q2s
其中q是奇數。若s=1,即p≡
3mod
4 p≡3
mod4
由尤拉判定直接解出r≡
np+1
4mod
p r≡n
p+14
modp
對於其他情況,隨機選擇乙個z(這個跟cipolla很像),使得(z
p)=−
1 (zp
)=−1
,令c≡
zqmodp
c ≡z
qmod
p,並令r≡
nq+1
2 r≡n
q+12
t≡nq t≡n
qm=s
m =s
(1)若t≡
1 t≡
1,r就是乙個解,另乙個解是p-r。
(2)否則,找乙個最小的i,
0<
i<
i<
m,使得t2i
≡1t 2i
≡1
令b≡c2m−
i−1 b≡c
2m−i
−1
,r≡rb r≡r
b,t
≡tb2
t ≡t
b2
,c≡b2 c≡b
2,m
=im =i
,重複(1)。
#include
#include
#include
#include
using namespace std;
#define ll long long
ll qp(ll a, ll b, ll p)
return tmp;
}ll le(ll n, ll p)
ll solve(ll n, ll p)
if (s == 1)
ll z;
while (true)
ll c = qp(z, tp, p);
ll r = qp(n, (tp + 1) >> 1, p), t = qp(n, tp, p), m = s;
while (true)
ll po = 1;
for (int i = 1; i <= m - i - 1; i++)po <<= 1;
ll b = qp(c, po, p);
// ll b=qp(c,1
<<(m-i-1),p);
r = r*b
%p; t = t*b
*b%p;
c = b*b
%p; m = i;
}return0;}
int main()
if (le(n, p) + 1 == p)
ll a = solve(n, p);
ll b = p - a;
if (a > b)std::swap(a, b);
if (a == b)
else
printf("%lld
%lld\n", a, b);
}return
0;}
二次剩餘小結
對於模數 n 和整數 a 若存在整數 x 滿足 x 2 equiv a mod n 則稱 x 是模 n 意義下的二次剩餘,否則是非二次剩餘 注 這裡討論的 x 滿足 x in 1,n 尤拉判別法 對於奇素數 p a 是模 p 意義下的二次剩餘當且僅當 a equiv 1 mod p 類似的,若 a ...
二次剩餘小記
看 text 的部落格看到的,發現似乎並沒有想象中的那麼難,就學了一下,過了板題,這裡記錄一下,暫時還是只會二次剩餘,n 次剩餘暫時先放一下。下文的 p 即是模數。我們稱 n 為模 p 意義下的二次剩餘當且僅當存在 x 使得 x 2 equiv n pmod p,x in mathbb 下文的 ma...
二次剩餘雜記
參考資料一 參考資料二 對於 x 和 p 如果存在 a in 0,p 滿足 a 2 equiv x pmod p 則稱x為模 p 的二次剩餘。在這裡,我們暫時只討論 p 為奇素數的情況。有乙個性質,二次剩餘與非二次剩餘的個數均為 frac 2 如果 p 的原根為 g 那麼 g 的偶數次冪顯然都是二次...