使用Make構建Node.js網站專案
簡介
\(\quad\)簡單說一下尤拉函式是什麼:
\(\quad\)我們定義 \(\varphi(x)\) 為小於等於x的正整數中與x互質的數的個數,特殊的 \(\varphi (1)=1\)
\(\quad\)通式:
\[\varphi(x)=x\times \Pi_{i=1}^{n}(1-\frac{1}{p_i}) \]\(\quad\)其中 \(p_i\) 為 \(x\) 的質因子,\(n\) 為 \(x\) 的質因子個數
章節涉及
- 尤拉函式的常用性質
- 尤拉定理和擴充套件尤拉定理
- 尤拉函式反演
尤拉函式的常用性質
\(\quad\)積性函式:對於任意 \(gcd(a,b)=1\)
\(\quad\)若 \(f\) 是積性函式,且在算數基本定理中 \(n=\Pi_{i=1}^{k}p_i^{c_i}\),則 \(f(n)=\Pi_{i=1}^{k}f(p_i^{c_i})\)
一些性質:
- 若 n 為質數,那麼 \(\varphi(n)=n-1\)
- 尤拉函式是積性函式
- 對於 \(x\) 為奇數時,\(\varphi(2\times x)=\varphi(x)\)
- 若 \(p\) 為質數,則 \(\varphi(p^k)=p^k-p^{k-1}\)(因為不與 \(p^k\) 互質的數只有 p 的倍數,而 p 的倍數又有 \(p^{k-1}\)
- 當 x>2 時,\(\varphi(x)\) 為偶數(gcd(a,a-x)=gcd(a,x),所以 gcd=1都是成對出現)
- 小於 n 的數中,與 n 互質的數的和為 \(\varphi(n)*n/2\) (參照性質5,每一對的平均數為 \(\frac{n}{2}\))
- 對於所有 \(n=\sum_{i=1}^{x} \varphi(p_i)\),\(p_i\) 為 n 的所有因數,x 為 n 的因數個數
- 若質數 \(p\mid n\),且 \(p^2\mid n\),那麼 \(\varphi(n)=\varphi(\frac{n}{p})\times (p)\)
- 若質數 \(p\mid n\)
根據 9 . 10 條性質,和線性篩,我們引出 線性求尤拉函式
code:
const int N=1e7+5,M=N/10;
int n,tot,p[M],phi[N],np[N];
bool f[N];
int T;
void urler(int n)
{
phi[1]=1;
for(int i=2;i<=n;i++)
{
if(!np[i])//記錄素數
{
p[++tot]=i;
phi[i]=i-1;
}
for(int j=1;j<=tot && i*p[j]<=n;j++)//經典尤拉篩模板
{
np[i*p[j]]=1;//合數先打上標記
if(i%p [j]=0)//保證每個數被自己的最小質因數篩去
{
phi[i*p[j]]=phi[i]*p[j];//性質9
break;
}
else
{
phi[i*p[j]]=phi[i]*phi[p[j]];//性質10
}
}
}
}
例題
\(\quad\)考慮每一個素數的貢獻
\(\quad\)對於 \(gcd(a\times p,b\times p)=p\),\(gcd(a,b)=1\)
\(\quad\)也就是對於 \(1\leq a,b\leq \frac{n}{p}\),有多少對 \((a,b)\) 互質。
\(\quad\)那就是尤拉函式+字首和。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e7+5,maxm=1e6+5;
int n,tot,p[maxm],pri[maxn];
long long sum[maxn];
bool f[maxn];
void sieve(int n)
{
pri[1]=1;
for(int i=2;i<=n;i++)
{
if(!f[i])
{
p[++tot]=i;
pri[i]=i-1;
}
for(int j=1;j<=tot && i*p[j]<=n;j++)
{
f[i*p[j]]=1;
if(i%p[j]=0)
{
pri[i*p[j]]=pri[i]*p[j];
break;
}
else
{
pri[i*p[j]]=pri[i]*pri[p[j]];
}
}
}
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+pri[i];
}
int main()
{
cin>>n;
sieve(n);
long long ans=0;
for(int i=1;i<=tot;i++) ans+=2*sum[n/p[i]]-1;
cout<<ans;
return 0;
}
尤拉定理和擴充套件尤拉定理
尤拉定理:
\(\quad\)若 \(a,m\) 互質,\(a^{\varphi(m)}\equiv 1 \pmod m\)
擴充套件尤拉定理:
\(\quad\)若\(b>\varphi(m)\),即使 \(gcd(a,m)>1\) ,\(a^b \equiv a^{b\space mod \space \varphi(m)+\varphi(m)} \pmod m\)
\(\quad\)當 \(gcd(a,m)=1\) 時,對於任意正整數b ,\(a^b\equiv a^{b\space mod \space \varphi(m)}\pmod m\)
例題
\(\quad\)這個 2 的次方是無限大,很明顯這個應該是和擴充套件尤拉定理有點關係的,2 的次方大於模數p。那麼這就是個遞迴了,當遞迴到模數 p=1 時,就餘數就等於0。
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+5,M=N/10;
int n,tot,p[M],phi[N],np[N];
bool f[N];
int T;
void urler(int n)
{
phi[1]=1;
for(int i=2;i<=n;i++)
{
if(!np[i])
{
p[++tot]=i;
phi[i]=i-1;
}
for(int j=1;j<=tot && i*p[j]<=n;j++)
{
np[i*p[j]]=1;
if(i%p[j]=0)
{
phi[i*p[j]]=phi[i]*p[j];
break;
}
else
{
phi[i*p[j]]=phi[i]*phi[p[j]];
}
}
}
}
int pow(int x,int p,int mod)
{
int ret=1;
while(p)
{
if(p&1)
{
ret=1ll*ret*x%mod;
}
x=1ll*x*x%mod;
p>>=1;
}
return ret;
}
int solve(int p)
{
if(p==1) return 0;
return pow(2,solve(phi[p])+phi[p],p);
}
int main()
{
urler(N);
cin>>T;
while(T--)
{
cin>>n;
cout<<solve(n)<<endl;
}
return 0;
}
尤拉函式反演
\(\quad\)利用尤拉函式的一條性質
\[n=\sum_{d\mid n}\varphi(d) \]\(\quad\)我們嘗試將 n 換成其他的東西
\[\sum_{i=1}^{n}gcd(i,n)=\sum_{i=1}^n\sum_{d\mid i}\sum_{d\mid n}\varphi(d)=\sum_{d\mid n}\sum_{i=1}^n\sum_{d\mid i}\varphi(d)=\sum_{d\mid n}\frac{n}{d}\varphi(d) \]\(\quad\)把它重寫一遍作為結論:
\[\sum_{i=1}^{n}gcd(i,n)=\sum_{d\mid n}\frac{n}{d}\varphi(d) \]例題
\(\quad\)繼續用上面的結論:
\[\sum_{i=1}^n\sum_{j=1}^n\sum_{d\mid i,j}\varphi(d)=\sum_{d=1}^n\varphi(d)\times\frac{n}{d}\times\frac{n}{d} \]\(\quad\)然後這裡的 \(\frac{n}{d}\) 可以用數論分塊優化