Miller Rabin 詳解 && 小清新數學題題解


在做這道題之前,我們首先來嘗試簽到題

簽到題

我們定義一個函數:\(qiandao(x)\) 為小於等於 x 的數中與 x 不互質的數的個數。要求 \(\sum\limits _{i=l}^r qiandao(i)\)

容易發現 \(qiandao(x)\) 只需求 \(\phi(x)\),不互質的個數就是另外一半。

那么問題轉化為了如何篩出區間 \(\phi\) 的值。考慮到值域最大只有 \(1e12\)。並且區間長度小於一百萬,所以可以嘗試篩根號以內素數求解。

我們知道歐拉函數計算公式為 \(\prod_{d \mid p}\frac{d-1}{d}\) 其中 d 是 p 的質因數。

於是我們可以通過篩去根號以內每個質數計算大整數區間的歐拉值,而剩下篩不掉的一定是大於根號的質數,這個直接根據上式乘上就行了。

復雜度與自然對數有關,和調和級數類似。

小清新數學題

求解 \(\sum\limits_{i=l}^r\mu(i)\)

現在我們掌握了區間篩積性函數的方法,但是,這道題的數據范圍到了 \(1e18\)。我們不可能曬出十億以內的質數。

那么怎么辦呢?

注意到本題求得是莫比烏斯函數,根據莫比烏斯函數的定義,函數值只與質因子的個數有關,我們不需要求出具體的質數是誰,只需要知道有幾個就行。

於是我們仍然可以用一百萬以內的質數去篩。

剩下的情況分三種:

  1. \(res=q\times p\)
  2. \(res=q\)
  3. \(res=q^2\)

首先對於第一種情況,莫比烏斯函數值並不會改變。

第二種情況,取反即可。

第三種情況,直接就是 0。

第三種情況好判斷,只需判斷是否滿足 \(\sqrt{i}^2==i\)

對於一二種情況,實質實在判斷 res 是否是素數,於是引出了我們的另一個問題。如何判斷一個數是否是素數?

Miller_Rabin 算法

百度百科:

Miller-Rabin算法是目前主流的基於概率的素數測試算法,在構建密碼安全體系中占有重要的地位。通過比較各種素數測試算法和對Miller-Rabin算法進行的仔細研究,證明在計算機中構建密碼安全體系時, Miller-Rabin算法是完成素數測試的最佳選擇。通過對Miller-Rabin 算 法底層運算的優化,可以取得較以往實現更好的性能。[1] 隨着信息技術的發展、網絡的普及和電子商務的開展, 信息安全逐步顯示出了其重要性。信息的泄密、偽造、篡改 等問題會給信息的合法擁有者帶來重大的損失。在計算機中構建密碼安全體系可以提供4種最基本的保護信息安全的服 務:保密性、數據完整性、鑒別、抗抵賴性,從而可以很大 程度上保護用戶的數據安全。在密碼安全體系中,公開密鑰 算法在密鑰交換、密鑰管理、身份認證等問題的處理上極其有效,因此在整個體系中占有重要的地位。目前的公開密鑰 算法大部分基於大整數分解、有限域上的離散對數問題和橢 圓曲線上的離散對數問題,這些數學難題的構建大部分都需 要生成一種超大的素數,尤其在經典的RSA算法中,生成的素數的質量對系統的安全性有很大的影響。目前大素數的生 成,尤其是隨機大素數的生成主要是使用素數測試算法,本 文主要針對目前主流的Miller-Rabin 算法進行全面系統的分析 和研究,並對其實現進行了優化

這個看個熱鬧就完了,其實這個東西我們只用來判斷一個數是否是素數。以下內容說到的 p 默認為質數。

Miller Rabin基於費馬小定理:

\[a^{p-1}\equiv 1\pmod{p} \]

證明:

  1. 對於數 \(a,2a,3a,.....(p-1)a\) 沒有 \(p\) 的倍數。

  2. 對於這一列數在模 \(p\) 意義下兩兩不同余。

  3. 這串數在模 \(p\) 意義下的余數構成 \(p-1\) 的一個排列。
    於是有:

\[a\times 2a\times 3a\times (p-1)a\equiv (p-1)!\pmod{p} \]

化簡左邊:

\[a^{p-1}\times (p-1)!\equiv (p-1)!\pmod{p} \]

由威爾遜定理:

\[(p-1)!\equiv1\pmod{p} \]

消去 \((p-1)!\) 得證。

費馬小定理成立,那么如果費馬小定理的逆命題成立我們不就可以判斷質數了嗎?

可惜,很長時間里人們確實是這樣認為的,直到強偽素數被人們發現,例如341。

再來介紹 二次探測定理:

如果滿足\(x^2\equiv1\pmod{p}\) 那么 x 的取值只有 1 或者 p-1。

證明:

轉換上式:

\[p\mid x^2-1 \]

\[p\mid (x-1)(x+1) \]

由唯一分解定理得到\(p \mid x+1\)\(p\mid x-1\)

所以 \(x\equiv1 or -1\pmod{p}\)

如果 x 不滿足上式則 p 一定是合數。

所謂 Miller Rabin 就是上面的結合。說白了就是多取幾個數多試幾次,這樣出錯的概率極低。

簽到題code

#include<bits/stdc++.h>
#define int long long 
#define mod 666623333
using namespace std;
int su[10000001],cnt,ans[1000011],len,lst=0,l,r,shu[1000011];
bool bo[10000001];
inline void pre()
{   for(int i=2;i<=1000000;++i)
    {   if(!bo[i])su[++cnt]=i;
        for(int j=1;j<=cnt and i*su[j]<=1000000;++j)
        {   bo[su[j]*i]=1;
            if(i%su[j]==0)break;
        }
    }
}
signed main()
{   pre();scanf("%lld%lld",&l,&r);len=r-l+1;
    for(int i=1;i<=len;++i)ans[i]=shu[i]=i+l-1;
    for(int i=1;i<=cnt;++i)
    {   int base=l/su[i];
        for(int j=base;;++j)
        {   if(j*su[i]>=l and j*su[i]<=r)
            {   ans[j*su[i]-l+1]=(ans[j*su[i]-l+1]/su[i]*(su[i]-1));
                while(shu[j*su[i]-l+1]%su[i]==0)shu[j*su[i]-l+1]/=su[i];
            }
            else if(j*su[i]>r)break;
        }
    }
    for(int i=1;i<=len;++i)
    {   if(shu[i]!=1)ans[i]=ans[i]/shu[i]*(shu[i]-1);
        lst=(lst+(l+i-1-ans[i]))%mod;
    }
    printf("%lld\n",lst);
}

小清新數學題code

#include<bits/stdc++.h>
#define int long long 
#define N 1000500
#define mfb __int128
using namespace std;
int su[N],cnt,tot,u[N],shu[N];
bool bo[N];long long l,r,ans;
inline int qpow(mfb a,mfb b){int mod=b+1,base=1;a%=mod;while(b){if(b&1)base=base*a%mod;a=a*a%mod;b>>=1;}return base;}
inline bool miller(int x)
{return (qpow(2,x-1)==1 );}
signed main()
{   scanf("%lld%lld",&l,&r);u[1]=1;
    int lim=1e6;
    for(int i=2;i<=lim;++i)
    {   if(!bo[i])su[++cnt]=i,u[i]=-1;
        for(int j=1;j<=cnt and i*su[j]<=lim;++j)
        {   bo[i*su[j]]=1;u[i*su[j]]=-u[i];
            if(i%su[j]==0){u[i*su[j]]=0;break;}
        }
    }
    for(int i=l;i<=r;++i)u[i-l+1]=1,shu[i-l+1]=i;
    for(int i=1;i<=cnt;++i)
    {   int be=l/su[i]+(l%su[i]!=0);
        for(int j=be;j*su[i]<=r;++j)
        {   int id=j*su[i]-l+1;
            int cnt=0;
            while(shu[id]%su[i]==0)shu[id]/=su[i],++cnt,u[id]*=-1;
            if(cnt>=2)u[id]=0;
        }
    }
    for(int i=l;i<=r;++i)if(shu[i-l+1]!=1)
    {   if((long long )sqrt(shu[i-l+1])*sqrt(shu[i-l+1])==shu[i-l+1]){u[i-l+1]=0;continue;}
        if(miller(shu[i-l+1]))u[i-l+1]*=-1;
    }
    for(int i=l;i<=r;++i)ans+=u[i-l+1];printf("%lld\n",ans);
}

由於數據比較水,我又比較懶,上面只用了 femart。

Miller Rabin

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100000+5;
int a[3]={2,7,61};
ll qm(ll x,ll y,ll mod){
    ll ret=1;
    while(y){
        if(y&1) (ret*=x)%=mod;
        (x*=x)%=mod;
        y>>=1;
    }
    return ret;
}
bool che(ll a,ll x){
    int s=0;
    ll t;
    ll lp=x-1;
    while(!(lp&1)){
        s++;
        lp>>=1;
    }
    t=qm(a,lp,x);
    if(t==1||t==x-1) return true;
    if(s==0) return false;
    ll las=t;
    for(int i=0;i<s;i++){
        las=t;
        (t*=t)%=x;
        if(t==1&&(las!=1&&las!=x-1)) return 0;    
    }
    if(t!=1) return 0;
    return 1;
}
int n,m;
bool M_R(ll n){
    if(n==2||n==7||n==61) return true;
    if(n<2||n%2==0||n%7==0||n%61==0) return false;
    for(int i=0;i<3;i++){
        ll b=a[i];
        if(b!=n){
            if(!che(b,n)) return false;
        }
    }
    return true;
}
int main(){
    scanf("%d%d",&n,&m);
    ll x;
    for(int i=1;i<=m;i++){
        scanf("%lld",&x);
        if(x==2||x==3||x==5||x==7||x==11||x==13){
            puts("Yes");continue;
        }
        if(x%2==0||x%3==0||x%5==0||x%7==0||x%11==0||x%13==0){
            puts("No");continue;
        }
        if(M_R(x)) puts("Yes");
        else puts("No");
    }
    return 0;
}

Miller Rabin的板子為轉載,上面過的是線性篩。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM