1. 程式人生 > 其它 >淺談高次方程之二次剩餘

淺談高次方程之二次剩餘

前言:

我們知道高次方程有兩種,在這一章我們來討論這一種

但我們只討論a=2的特殊情況。

因為作者本身水平很弱,在此並不過多的說一些很學術的詞語或證明,有的甚至不會給出證明,如有需要請自行度娘。

在本章的篇幅會大量傾斜於how,而不是why。如果你只想明白該怎麼解,那麼您可以繼續讀下去。

在此預設大家都知道(https://kewth.github.io/2019/10/21/%E4%BA%8C%E6%AC%A1%E5%89%A9%E4%BD%99/)這個網址上的東西。

有一個演算法可以來解決這類問題,Cipolla演算法。但是有個限制就是p為奇素數。

這個演算法大概是什麼步驟呢?

首先我們要判斷n是否有解。

定義關於n和p的一種符號勒讓德記號

當(n)=1時,n一定有解。

當 (n) =-1時,n一定無解。

判斷完n是否有解,我們可以知道,n的解應該有兩個,且互相為modp意義下的相反數。

下面推出一個重要定理

a怎麼求呢?我們知道二次剩餘的數量為(p-1)/2,所以非二次剩餘為(p-1)/2,所以我們可以選隨機數。五五開的概率,2,3次估計就出來了。

求出了一個a,就求出了w,就求出了一個x。但w可能是個虛數,x可能是個虛數。根據拉格朗日定理,這裡的x的虛部係數為0,所以x不為虛數。但我們仍需要在w的運算中使用複數運算。

類似的,給出複數運算的程式碼:

num mul(num a,num b,ll p)
{
    num ans
={0,0}; ans.x=(((a.x*b.x%p+a.y*b.y%p*w%p))%p+p)%p; ans.y=((a.x*b.y%p+a.y*b.x%p)%p+p)%p; return ans; }

可以對著看一下。

複數的表示:

struct num
{
    ll x,y;
};

x為整數部分,y為複數係數,此處複數以w為單位。

然後這個演算法就差不多了,下面給出模板題程式碼:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll w;
struct num
{
    ll x,y;
};
//複數定義 ll ksm(ll a,ll b,ll p) { ll ans=1; while(b) { if(b&1) ans=1ll*ans%p*a%p; a=a%p*a%p; b>>=1; } return ans%p; }//快速冪 num mul(num a,num b,ll p) { num ans={0,0}; ans.x=(((a.x*b.x%p+a.y*b.y%p*w%p))%p+p)%p; ans.y=((a.x*b.y%p+a.y*b.x%p)%p+p)%p; return ans; }//複數乘法 ll powi(num a,ll b,ll p) { num ans={1,0}; while(b) { if(b&1) ans=mul(ans,a,p); a=mul(a,a,p); b>>=1; } return ans.x%p; }//複數快速冪 ll solve(ll n,ll p) { n%=p; if(p==2) return n;//特判減少常數 if(ksm(n,(p-1)/2,p)==p-1) return -1; ll a; while(1) { a=rand()%p; w=((a*a%p-n)%p+p)%p; if(ksm(w,(p-1)/2,p)==p-1) break ; }//求a num x={a,1};//複數初定義 return powi(x,(p+1)/2,p); } int main() { srand(time(0)); int t; cin>>t; while(t--) { ll n,p; cin>>n>>p; if(!n) { cout<<0<<endl; continue; } ll ans1=solve(n,p),ans2; if(ans1==-1) cout<<"Hola!"<<endl; else { ans2=p-ans1; if(ans1>ans2) swap(ans1,ans2); if(ans1==ans2) cout<<ans1<<endl; else cout<<ans1<<' '<<ans2<<endl; } } return 0; }

好的,就到這裡結束了。但其實這個演算法中間有很多證明過程我沒寫,有的我也不太懂,但解題誰還管你證明?(手動狗頭)話說我開始給的網址講的算比較詳細了,但下面複數運算就沒講了,於是我又去百度&&洛谷題解區找了找,最後整合成這篇文章。(大體還行,細節就別細究了

總結:

哎,寫部落格真好玩啊。(又在水總結)等我數學功底強一點了,我再去挑戰高次方程的巔峰方程吧。(手動狗頭)