線性(尤拉)篩&尤拉函式
線性篩法
what is 線性篩??就是基於最基本的篩法的優化。
在基礎的篩法上,我們發現有的數字會被重複篩,例如6既會被2列舉到也會被3列舉到,必然有重複運算。
我們的做法就是讓每一個數的最小因數篩。
\(FOR\) \(EXAMPLE:\)
有一個數\(2 * 2 * 3 * 5\)
有另一個數 \(3 * 3 * 3* 5\)
那麼第一個數列舉到3的話,篩到的數字是\(2 * 2 * 3 * 3 * 5\)
但是在第二個數字再次列舉的時候 列舉到2時 也會列舉到\(2 * 2 * 3 * 3 * 5\)
因此,維護這個最小質因數即可。
怎麼維護??
當\(i\) \(mod\) \(這個質因數\)
#include<bits/stdc++.h> using namespace std; int main() { int n,cnt=0; int prime[10000]={};//用來儲存素數 int Vis[10000]={};//用來判斷是否是素數 cin>>n; for (int i=2;i<=n;i++) { if (Vis[i]==0) prime[++cnt]=i;//如果沒有被標記過 for (int j=1;j<=cnt&&i*prime[j]<=n;j++)//用i去乘上每一個已經求過的素數 { Vis[i*prime[j]]=1;//標記素數 if (i%prime[j]==0) break;//下面再解釋 } } for (int i=2;i<=n;i++) if (Vis[i]==0) cout<<i<<' '; return 0; }
一、尤拉函式概念
尤拉函式,是表示1~n中與n互質的元素的個數,記為\(φ(n)\)。
二、性質
- 如果n為某一素數p,顯然\(φ(p)\)為p-1
- 如果n為某一素數的冪次,那麼: \[\phi(p^a)=(p-1)*p^ {a-1}\]
我們可以來推導次函式的求法
我們先將n分解質因數得:
\[n=a1^{b1}*a2^{b2}*a3^{b3}*……*ak^{bk}\]
因為φ(n)求的是與n互質的數的個數,所以其中不能有n的因數,即不能出現a1,a2,a3……ak的倍數。
那麼我們來轉換思路,n個數之中存在多少個a1的倍數,多少個a2的倍數……多少個ak的倍數呢?
顯然有n/a1個a1的倍數,n/a2個a2的倍數……有n/ak個ak的倍數。
所以\(φ(n)=n-\frac{1}{a1} -\frac{1}{a2}-\frac{1}{a3}-……-\frac{1}{ak}\)
將n提取出來得到:
\[φ(n)=n*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})\]
於是尤拉函式的公式就這麼推匯出來了
還有如下性質:
- 如果i mod p=0,那麼\(φ(i*p)=p*φ(i)\)
證明:
對於公式\[φ(1)=n*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})\]
得到
\[φ(n)=n*p*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})\]
因為p已經是i的因數,後半部分不需要新增
因此得證。 函式的積性,\(φ(i*j)=φ(i)*φ(j)\)
如果i mod p≠0,那麼\(φ(i*p)=φ(i)*(p-1)\)
根據
\[φ(n)=n*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})\]
得到
\[φ(n)=n*p*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})*(1-\frac{1}{p})\]
因為p不是i的因數,因此最後要加上\((1-\frac{n}{ak})\)部分。
證明完成。
三、求法
下面給兩種求法。
\(1\).公式法
根據公式\(φ(n)=n*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})*(1-\frac{1}{p})\)
inline LL eular(LL x)
{
LL sum=x,y=x;
for (LL i=2;i*i<=y;++i)
{
if (x%i!=0) continue;
sum=sum/i*(i-1);
while (x%i==0) x/=i;
}
if (x>=2) sum=sum/x*(x-1);
return sum;
}
//公式求x尤拉函式
\(2\).線性篩求尤拉函式
根據三條性質推導即可。
線性篩中每一個數字最多隻會被篩一次,因此正好可以對每一個數字求尤拉函式。
線性篩正好是由小的數字篩到大的數字 or 正好是指數
前者用後兩條性質 後者用第一條性質即可。
三條性質如下:
- 如果n為某一素數的冪次,那麼: \(\phi(p^a)=(p-1)*p^ {a-1}\)
- 如果i mod p=0,那麼\(φ(i*p)=p*φ(i)\)
- 如果i mod p≠0,那麼\(φ(i*p)=φ(i)*(p-1)\)
inline void findphi(void)
{
phi[1]=1,prm[1]=0;
for (LL i=2;i<=n;++i)
{
if (!v[i]) { prm[++cnt]=i, phi[i]=i-1; }
for (LL j=1;j<=cnt && i*prm[j]<=n;++j)
{
v[i*prm[j]]=1;
if (i%prm[j]==0) { phi[i*prm[j]]=phi[i]*prm[j]; break; }
if (i%prm[j]!=0) phi[i*prm[j]]=phi[i]*(prm[j]-1);
}
}
return;
}
後記
部分參考hkh大佬的部落格。
在此表示感謝!
如有紕漏請讀者指正!
<\font>