前排提醒:如無特殊說明,本文中所有符號與《初等數論》(第三版,潘承洞 潘承彪著),北京大學出版社一書中意義相同
關於Euler 函數φ(x)
Euler 函數φ(x) 的定義與基本性質
本着定義是重中之重的原則,我們先來回顧一下
對於任意正整數
n ,我們記小於n 且與n 互素的正整數的個數φ(m) 爲m 的Euler函數。即:φ(m)=∑d≤m[(m,d)=1]
由定義立即可推出它的一些簡單的性質:
φ(m)=m 的既約剩餘系的個數。特別地,對於素數p,φ(p)=p−1 - 設
m=m1m2 ,若m1 和m2 的素因子集合相同,那麼φ(m)=m2φ(m1) - 設
m=m1m2 ,若(m1,m2)=1, 那麼φ(m)=φ(m1)φ(m2), 即Euler 函數φ(x) 是積性函數 - 記
m 的標準分解爲m=∏pαii, 則有φ(m)=m∏(1−1pi) - 對於任意正整數
m ,都有m=∑d|mφ(d)
這些性質都比較顯然,在這裏不作證明
φ(x) 的計算方法
如果只是詢問一個數的函數值,最顯然的思路就是O(
inline int phi(int x)
{
int ans=x;
for(int i=2;i<=sqrt(x);i++) if(x%i==0)
{
ans-=ans/i;
while(x%i==0) x/=i;
}
return ans;
}
但更多的時候我們是需要求很多很多的
我們發現可以在篩素數的時候順手處理
//Eratosthenes篩法,時間複雜度O(n log log n)
void init()
{
for(int i=1;i<=maxn;i++) phi[i]=i;
for(int i=2;i<=maxn;i++) if(!vis[i])
{
prime[++cnt]=i; phi[i]--;
for(int j=i*2;j<=maxn;j+=i) vis[j]=1,phi[j]-=phi[j]/i;
}
}
//線性篩法,時間複雜度O(n)
void init()
{
for(i=2;i<=maxn;i++)
{
if(!vis[i]) prime[++cnt]=i,phi[i]=i-1;
for(int j=1;j<=cnt&&i*prime[j]<=maxn;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]) phi[i*prime[j]]=phi[i]*(prime[j]-1);
else
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
}
}
}
關於Mobius 函數μ(x)
Mobius 函數μ(x) 的定義與性質
廢話不多說,直接上定義:
對於正整數
n>1 ,記其標準分解爲則有n=∏i=1rpαii μ(x)={(−1)r0α1=α2=⋯=αr=1else
特別地,有μ(1)=1
從以上定義,可以推出以下幾點性質:
- 若
μ(x)≠0 ,則x 沒有比1 大的平方數因子 - 若
(m1,m2)=1 ,則有μ(m1m2)=μ(m1)μ(m2) ,即Mobius 函數μ(x) 是積性函數 - 對於任意正整數
n ,都有∑d|nμ(d)={10n=1n≠1 - 對於任意正整數
n ,都有這裏μ(m)=∑xmodme2πixm xmodm 表示對m 的任意一組既約剩餘系求和
前兩個性質比較顯然,下面對性質3與性質4做出簡略的證明
性質3:
n=1 時,命題顯然成立。
n>1 時,記n 的素因子個數爲r ,則由Mobius 函數的定義,有∑d|nμ(d)=C0r−C1r+⋯+(−1)rCrr=(1−1)r=0 性質4:
由複數相關知識,對於任意正整數
c ,顯然有∑i=1me2πicxm={m0m|celse
記m 的標準分解爲設m=∏i=1rpαii mj=pαjj(1≤j≤r) 以及mjMj=m ,由數論的相關定理,當x(j) 分別遍歷模mj 的縮系時,遍歷模x=∑i=1rMix(i) m 的縮系,於是有S(m)=∑xmodme2πixm=∑x(1)modm1⋯∑x(r)modmre2πi(M1x(1)+M2x(2)+⋯+Mrx(r))m=S(m1)S(m2)⋯S(mr)
容易看出於是性質4得證。S(pαjj)=∑x=1pαjjexp⎛⎝2πixpαjj⎞⎠−∑x=1pαj−1jexp⎛⎝2πixpαj−1j⎞⎠={−10αj=1αj>1
μ(x) 的計算方法
和
inline int miu(int x)
{
int ans=1;
for(int i=1;i<=sqrt(x);i++) if(x%i==0)
{
ans=-ans,x/=i;
if(x%i==0) return 0;
}
return x>1?-ans:ans;
}
至於多點求值,考慮到
void init()
{
miu[1]=1;
for(int i=2;i<=maxn;i++)
{
if(!vis[i]) prime[++cnt]=i,miu[i]=-1;
for(int j=1;j<=cnt&&i*prime[j]<maxn;j++)
{
int t=i*prime[j]; vis[t]=1;
if(i%prime[j]==0) {miu[t]=0; break;}
miu[t]=-miu[i];
}
}
}
好啦,基礎知識先介紹這麼多,可以開始做題了。
典型習題
BZOJ2705 歐拉函數
題意:
給定正整數
分析:
將
由於
時間複雜度:
下面貼出代碼:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int N,m;
LL ans;
inline LL read()
{
LL ans=0; char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
return ans;
}
inline LL phi(LL u)
{
LL ans=u;
for(int i=2;i<=sqrt(u);i++) if(u%i==0)
{
ans-=ans/i;
while(u%i==0) u/=i;
}
if(u>1) ans-=ans/u;
return ans;
}
int main()
{
N=read(),m=sqrt(N);
for(int i=1;i<=m;i++) if(N%i==0)
{
ans+=i*phi(N/i);
if(N/i!=i) ans+=N/i*phi(i);
}
printf("%lld",ans);
return 0;
}
BZOJ2818 Gcd
題意:
給定
分析:
還是上一題的套路,
其中
時間複雜度:
BZOJ2005 能量採集
這裏用到數論中的一個結論:長爲
由此可知所求答案即爲
我們不妨假設總有
好了,做完了。
時間複雜度同上一題。
SPOJ-VLATTICE
說白了就是求在集合
因爲含有數字0,所以分類討論。
座標軸上一共有三個點可視
由
綜上,最終答案爲
未完待續。