2020版本IDEA破解教程,輕鬆破解到2099年
很早就聽說過二次剩餘的概念了,但由於沒有一直碰到過相關的題目
加上學不太明白,所以一直拖啊拖沒去認真學,最近終於碰到了要用到二次剩餘相關知識的題,然後滾去認真學習了一波,現寫篇部落格記錄下所學所想。不然過幾天又忘了
二次剩餘在數論的研究和實際上好像有很廣泛的運用,但在演算法競賽中用的不多,一般是用來求解二次同餘式俗稱模意義開根 \(or\) 判斷一些有關多次同餘式的解的存在性問題。
考慮到高次剩餘和模數 \(p\) 為合數的情況比較少見我不會,這裡就不多加討論,我們只討論 \(p\) 為奇素數和 \(n\neq0\) 的情況,\(p=1、p=2、n=0\) 的情況顯然很好特判。
為了方便描述,我們約定,以下運算都是在模 \(p\) 意義下進行的,即同餘符號 \(\equiv\) 都省略了後面的 \({\rm mod}\ p\),且 \(n,x\in[1,p-1]\)。
定義
給定一個正整數 \(p\),若對於一個正整數 \(n\),存在整數 \(x\) 滿足 \(x^2\equiv n\pmod p\),則稱 \(n\) 是模 \(p\) 的二次剩餘,否則稱 \(n\) 為模 \(p\) 的二次非剩餘(或者說非二次剩餘)。
例如 \(4^2\equiv 1\pmod 5\),因此 \(1\)
性質
性質 1:模 \(p\) 意義下的二次剩餘 \(n\) 一共有 \(\displaystyle\frac{p-1}2\) 個(不包括 \(0\))。
證明:
直接討論 \(n\) 的數量的話感覺沒啥頭緒,但注意到這裡的每個 \(n\) 都對應著一個 \(x^2\),我們可以來試試討論 \(x^2\)。
顯然有 \(x^2\equiv(-x)^2\),而在模 \(p\) 意義下,\(-x\iff p-x\),因此只需討論 \(x\in[1,\displaystyle\frac{p-1}2]\),便可覆蓋到所有可能的 \(n\),既然只有 \(\displaystyle\frac{p-1}2\) 個不同的 \(x\),那麼顯然最多隻有 \(\displaystyle\frac{p-1}2\) 個對應的 \(n\),接下來我們只需證明這些 \(x\) 的平方模 \(p\) 兩兩不相等,即可得證。
證明這種取模兩兩不相等的套路一般都是反證法,可以參考這篇部落格對於完全剩餘系的性質的證明。
假設存在不同的兩個數 \(x,y\in[1,\displaystyle\frac{p-1}2]\) 且 \(x^2\equiv y^2\),則有 \((x+y)(x-y)\equiv 0\),顯然根據 \(x,y\) 的取值範圍,有 \(-p<x+y<p,\ -p<x-y<p,\ x+y\neq0,\ x-y\neq0\),即 \((x+y)(x-y)\) 不可能模 \(p\) 為 \(0\),故假設不成立,原命題得證。
性質 2:兩個二次剩餘相乘、或者兩個二次非剩餘相乘,得到的仍是一個二次剩餘。
性質 3:一個二次剩餘和一個二次非剩餘相乘,得到的是一個二次非剩餘。
性質 4:一個二次剩餘的逆元也是二次剩餘。
性質 2、3、4 都可由尤拉準則輕鬆證出,故此處證明略。
勒讓德符號(Legendre Symbol)
為了方便描述,我們定義勒讓德符號 \(\left(\displaystyle\frac np\right)\),它滿足:
\[\left(\frac np\right)=\begin{cases} 1\qquad \text{n 是模 p 的二次剩餘}\\ -1\quad\ \text{n 是模 p 的二次非剩餘}\\ 0\qquad \text{n 是0} \end{cases} \]尤拉準則
當你要判斷一個數 \(n\) 是不是模 \(p\) 的二次剩餘時,有:\(n\) 是模 \(p\) 的二次剩餘,當且僅當 \(n^{\frac {p-1}2}\equiv 1\) 。
證明:
充分性:當 \(n\) 是二次剩餘時,根據費馬小定理,我們有 \(n^{\frac{p-1}2}\equiv (x^2)^{\frac{p-1}2}\equiv x^{p-1}\equiv1\),充分性得證。
必要性:假設 \(g\) 為模 \(p\) 的一個原根,則一定有某個正整數 \(k\) 滿足 \(g^k\equiv n\),我們只需要取 \(x=g^{\frac k2}\),即可使得 \(x^2\equiv n\),接下來只需要證明 \(k\) 是偶數即可。
當 \(n^{\frac {p-1}2}\equiv 1\) 時,我們有 \(n^{\frac{p-1}2}\equiv (g^k)^\frac{p-1}2\equiv 1\),因為 \(g\) 是一個原根,所以當 \((g^k)^\frac{p-1}2\equiv 1\) 時一定有 \(p-1\mid k*\frac{p-1}2\),因此 \(k/2\) 一定是個整數,即 \(k\) 一定是偶數。
也就是說,當 \(n^{\frac {p-1}2}\equiv 1\) 時,一定存在某個數 \(x\) 使得 \(x^2\equiv n\),即 \(n\) 是一個二次剩餘,必要性得證。
同時由於 \(n^{\frac {p-1}2}\) 不是 \(1\) 就是 \(-1\)、\(n\) 不是二次剩餘就是二次非剩餘,所以 \(n\) 是二次非剩餘和 \(n^{\frac {p-1}2}\equiv -1\) 也是等價的,發現這剛好符合我們上面對勒讓德符號的定義,因此又有 \(n^{\frac {p-1}2}\equiv\left(\dfrac np\right)\)。
有了尤拉準則,上面的性質 \(2\) 和性質 \(3\) 也非常好證了,這裡簡單地證明一下性質 \(3\):
證明:設 \(n_1\) 是二次剩餘,\(n_2\) 是二次非剩餘,則有 \((\frac {n_1}p)\equiv1,\ (\frac{n_2}p)\equiv-1\iff n_1^{\frac{p-1}2}\equiv1,\ n_2^{\frac{p-1}2}\equiv-1\),那麼 \((n_1*n_2)^{\frac{p-1}2}\equiv n_1^{{\frac{p-1}2}}*n_2^{\frac{p-1}2}\equiv -1\),即 \(n1*n2\) 是一個二次非剩餘,得證。
Cipolla 演算法
可以在 \(O(\log p)\) 的時間內求解二次同餘方程 \(x^2\equiv n\pmod p\)。感覺有點玄學,涉及到複數域的推廣,並沒有理解的很明白,但總之先記錄下來吧。
演算法思路
1、找到一個數 \(a\) 滿足 \(a^2-n\) 是二次非剩餘。
2、定義 \(i^2\equiv a^2-n\),由於 \(a^2-n\) 是二次非剩餘,顯然這樣的 \(i\) 並不存在,但我們可以像實數推廣到複數域一樣,把模 \(p\) 的實數域擴張為複數域,用 \(A+Bi\) 來表示這個域中的所有數(虛數單位 \(i=\sqrt{a^2-n}\)),\(A,B\) 都是模 \(p\) 意義下的數。
3、則有 \((a+i)^{p+1}\equiv n\),解 \(x\) 即為 \((a+i)^{\frac{p+1}2}\)。
正確性證明
引理 1:\(i^p\equiv-i\)
證明:\(i^p\equiv i*(i^2)^{\frac{p-1}2}\equiv i*(a^2-n)^{\frac{p-1}{2}}\equiv-i\)。
引理 2:\((a+b)^p\equiv a^p+b^p\)
證明:二項式定理展開後,共有 \(p+1\) 項,每一項都是 \({\rm C}_p^ma^mb^{p-m},~m\in[0,p]\) 的形式,因為 \(p\) 為質數,所以除了 \(m=0\) 和 \(m=p\) 的兩項,其他項的 \({\rm C}_p^m\) 的分子都會有一個 \(p\) 約不掉,這些項模 \(p\) 都為 \(0\),因此最後只剩下兩項:\(a^p+b^p\) ,得證。
於是我們有:
\[\begin{aligned} (a+i)^{p+1}&\equiv(a+i)^p(a+i) \\ &\equiv (a^p+i^p)(a+i) \\ &\equiv (a^p-i)(a+i) \\ &\equiv (a-i)(a+i) \\ &\equiv a^2-i^2 \\ &\equiv n \end{aligned} \]則 \((a+i)^{\frac {p+1}2}\) 為方程的解 \(x\),其相反數是另一個解。
但這是拓展了數域的條件下所求得的答案,這個答案在原數域下也成立嗎?顯然如果要使答案在原數域下也成立,所求得的數的虛部就必須為 \(0\),接下來證明 \((a+i)^{\frac {p+1}2}\) 的虛部一定為 \(0\)。
證明:
反證法,假設 \((a+i)^{\frac {p+1}2}\equiv A+Bi\),且 \(B\neq0\)。
那麼我們有 \((A+Bi)^2\equiv A^2+2ABi+B^2i^2\equiv n\),移項並把 \(i^2=a^2-n\) 代入得 \(A^2+B^2(a^2-n)-n\equiv-2ABi\)。
同餘式左邊是常數,右邊肯定也是常數,所以 \(AB\equiv 0\),同時因為 \(B\neq0\),則 \(A\equiv 0\),從而有 \((Bi)^2\equiv n\iff i^2\equiv nB^{-2 }\),因為 \(n\) 是二次剩餘,\(B^2\) 是二次剩餘,所以 \(nB^{-2}\) 也是二次剩餘,這與 \(i^2\) 是二次非剩餘矛盾,所以 \(B\) 一定為 \(0\),得證。
時間複雜度分析
如何找到這樣的 \(a\) 滿足 \(a^2-n\) 是二次非剩餘?很簡單,我們只需隨機生成一個數 \(a\),然後用尤拉準則判斷 \(a^2-n\) 是否為二次非剩餘即可,因為二次剩餘的和二次非剩餘的數量都為 \(\dfrac {p-1}2\),所以整數域裡的某個數是二次非剩餘的概率約為 \(50\%\),因此隨機的期望次數是 \(2\) 次,每次都用尤拉準則 \(O(\log p)\) 判斷一下,時間複雜度是 \(O(\log p)\)。找到了 \(a\) 以後,只需用複數域上的快速冪即可求出解,時間複雜度 \(O(\log p)\),總時間複雜度 \(O(\log p)\)。
程式碼實現
Code
#include<bits/stdc++.h>
using namespace std;
long long n,p;
long long i;
struct td{ //自定義的複數
long long x,y;
td(long long xx=0,long long yy=0){
x=xx,y=yy;
}
td operator * (td a){ //等價於複數相乘
return td( (x*a.x+i*y%p*a.y)%p,
(y*a.x+x*a.y)%p);
}
};
long long qsm(long long a,long long b){
long long ret=1;
while(b){
if(b&1) ret*=a,ret%=p;
b>>=1,a*=a,a%=p;
} return ret;
}
td t_qsm(td a,long long b){
td ret(1,0);
while(b){
if(b&1){
ret=ret*a;
}
b>>=1,a=a*a;
} return ret;
}
bool legendre(long long n){ return qsm(n,(p-1)/2)==1; }
int main(){
int t; cin >> t;
mt19937 mt_rand(time(0)); //隨機性更好一些的隨機
while(t--){
cin >> n >> p;
if(n==0){ //特判0
cout <<"0\n";
continue;
}
if(legendre(n)){
long long a=mt_rand()%p;
while(legendre(a*a-n)){
a=mt_rand()%p;
}
i=(a*a+p-n)%p; //相當於複數的單位根
td ans=t_qsm(td(a,1),(p+1)/2); //答案即為 (a,1)^{(p+1)/2}
ans.x=min(ans.x,p-ans.x); //顯然有兩個答案 (x)^2 ≡ (p-x)^2
cout << ans.x << " " << p-ans.x << endl;
}
else cout << "Hola!\n";
}
}
參考資料
- 二次剩餘 - OI Wiki (oi-wiki.org)
- https://www.luogu.com.cn/blog/zhang-xu-jia/qian-tan-er-ci-sheng-yu
- https://www.luogu.com.cn/blog/Vectory/er-ci-sheng-yu
- https://blog.csdn.net/acdreamers/article/details/10182281
- https://blog.csdn.net/Estia_/article/details/88789451
- https://baike.baidu.com/item/%E4%BA%8C%E6%AC%A1%E5%89%A9%E4%BD%99/3990744?fr=aladdin
- https://kewth.github.io/2019/10/21/%E4%BA%8C%E6%AC%A1%E5%89%A9%E4%BD%99/