尤拉線性篩 和 尤拉函式的求值
PS:求逆元的部分在文章最後。。。最好也看看前邊的知識吧qwq
用篩法求素數的基本思想是:把從1開始的、某一範圍內的正整數從小到大順序排列, 1不是素數,首先把它篩掉。剩下的數中選擇最小的數是素數,然後去掉它的倍數。依次類推,直到篩子為空時結束。 (來自 百度百科)
一般的篩法(埃拉託斯特尼篩法)的效率是O(nlglgn),但出題人卡你可就涼了。。
(就不介紹了(逃))
下面我們來說O(n)的尤拉線性篩
埃篩之所以慢,是因為有些合數被重複篩除(如:6會被2和3重複篩)
但是尤拉篩保證
每一個數p,只會被其最小的素因子mp[p]篩一次
#define R register int const int M=1000010; int mp[M],//mp[i] 為i的最小素因子 prime[M],//prime[i] 代表2-n中的第i個質數 cnt;//素數計數 inline void Prime(int n)//篩的範圍 { for(R i=2;i<=n;i++) { if(!mp[i]) prime[++cnt]=mp[i]=i; for(R j=1,k=i*prime[j];j<=cnt&′[j]<mp[i]&&(k=i*prime[j])<=m;i++) mp[k]=prime[j]; } }
也有一些別的寫法,如
inline void Prime(int x) { for(int i=2;i<=x;i++) { if(!mp[i]) prime[++cnt]=i,mp[i]=i; for(int j=1;j<=cnt&&i*prime[j]<=x;j++) { mp[i*prime[j]]=prime[j]; if(i%prime[j]==0) break; //if(prime[j]>=mp[i]) break; } } }
if(i%prime[j]==0) break ; 這個很重要qwq
若 i%prime[j]==0,則 i=k*prime[j](k為正整數).
如果不 break,下一個迴圈中的 mp(i*prime[j+1])=prime[j+1],
就是 mp(k*prime[j]*prime[j+1])=prime[j+1],
但 顯然k*prime[j]*prime[j+1]的最小質因子為 prime[j] 而非 prime[j+1](prime[]陣列中的素數是遞增的)
所以應 break
if(prime[j]>=mp[i]) break;也可用這句話,一個意思,就是不能讓 i乘上的質因子 大於 i的最小質因子
尤拉函式。。。
在數論,對正整數n,尤拉函式是少於或等於n的數中與n互質的數的數目。此函式以其首名研究者尤拉命名,它又稱為Euler's totient function、φ函式、尤拉商數等。 例如φ(8)=4,因為1,3,5,7均和8互質。
所以求某個φ(p)可以有很樸素 (樸素的不行) 的求法:
//就是列舉每個素因子 inline int phi(int n) { R ans=1; for(R i=2;i*i<=n;++i) if(n%i==0) { n/=i; ans*=i-1; while(n%i==0) n/=i,ans*=i; } if(n>1) ans*=n-1; return ans; }
但如果求p∈[1,n],每個φ(p),那上面的演算法就太菜了。
數論上的積性函式f(x)滿足a與b互素時(a,b∈N + ),f(a·b)=f(a)·f(b),f(1)=1;
而φ(p)就是一個積性函式。
此時可以利用剛學的尤拉篩
正確性:
1.φ(p)是一個積性函式,當a與b互素時,滿足φ(a·b)=φ(a)·φ(b)。
2.當正整數p是素數時,φ(p)=p-1 (定義)
3.每個合數只會被篩到一次(前面說明過)。
4.當p是素數時,φ(p k )=(p-1)·φ(p k-1 ),因為有(p-1)個數與p互素
#define R register int const int N=10000010; int n,cnt,prime[N],p[N]; bool vis[N]; inline void Euler(int n) { vis[1]=true; for(R i=2;i<=n;i++) { if(!vis[i]) prime[++cnt]=i,p[i]=i-1; for(R j=1;j<=cnt&&i*prime[j]<=n;j++) { vis[i*prime[j]]=true; if(i%prime[j]==0) { p[i*prime[j]]=p[i]*prime[j]; break; } p[i*prime[j]]=(prime[j]-1)*p[i]; } } }//p[i]即為φ(i)
所以隆重推出......::::::
尤拉定理:
若p,a為正整數,且p,a互質,則:a^φ(p) ≡1 (mod p) (是不是有些眼熟)
其實尤拉定理相當於費馬小定理的擴充套件
所以我們可用其求乘法逆元:
a*a^(φ(p)-1) ≡1 (mod p)
a^(φ(p)-1)即為a mod p 意義下的逆元
#include<iostream> #include<cstdio> #include<cctype> #define R register int #define ll long long using namespace std; static ll a,p; inline ll q_pow(ll x,ll ind,ll mod) { x%=mod; register ll a=1; for(;ind;ind>>=1,(x*=x)%=mod) if(ind&1) (a*=x)%=mod; return a; } inline int phi(int n) { R ans=1; for(R i=2;i*i<=n;++i) if(n%i==0) { n/=i; ans*=i-1; while(n%i==0) n/=i,ans*=i; } if(n>1) ans*=n-1; return ans; } int main() { scanf("%lld%lld",&a,&p); printf("%lld\n",q_pow(a,phi(p)-1,p)); return 0; }
如有錯誤,懇請您指正(我太菜了);如有不理解,可留言,我會盡量回復。。。(高中生(逃)。。)
by Jackpei 2019.2.13