在数论中的积性函数:对于正整数n的一个算术函数 f(n),若f(1)=1,且当a,b互质时f(ab)=f(a)f(b),在数论上就称它为积性函数。若对于某积性函数 f(n) ,就算a, b不互质,也有f(ab)=f(a)f(b),则称它为完全积性的。
设f为算术函数,F为f的和函数,有F(n)=sigma[f(d)],d|n。我们现在要做的事是如何根据F求出f。
例如:
F(1)=f(1)
F(2)=f(1)+f(2)
F(3)=f(1)+f(3)
F(4)=f(1)+f(2)+f(4)
F(5)=f(1)+f(5)
F(6)=f(1)+f(2)+f(3)+f(6)
F(7)=f(1)+f(7)
F(8)=f(1)+f(2)+f(4)+f(8)
利用解方程,我们得到:
f(1)=F(1)
f(2)=F(2)-F(1)
f(3)=F(3)-F(1)
f(4)=F(4)-F(2)
f(5)=F(5)-F(1)
f(6)=F(6)-F(3)-F(2)+F(1)
f(7)=F(7)-F(1)
f(8)=F(8)-F(4)
观察发现,f(n)等于形式为+/-F(n/d),d|n,所以我们推论出莫比乌斯反演公式:
f(n)=sigma[u(d)*F(n/d)](一定要记住这个形式呀,否则后面你就不好理解了)。
现在试着确定u函数:
例如,对于上面的例子有u(1)=u(6)=1, u(2)=u(3)=u(5)=u(7)=-1,u(4)=u(8)=0。
继续观察:
若p是素数
F(p)=f(1)+f(p)=>f(p)=F(p)-F(1),那么u(p)=-1。
继续观察:
F(p^2)=f(1)+f(p)+f(p^2)=>f(p^2)=F(p^2)-(F(p)-F(1))-F(1)=F(p^2)-F(p),这又有u(p^2)=0。
同理我们推出f(p^3)=F(p^3)-F(p^2),这又有u(p^3)=0,就这样推下去,我们有当k>1,有u(p^k)=0。
继续观察:
设p1,p2为素数
F(p1*p2)=f(p1*p2)+f(p1)+f(p2)+f(1)=>f(p1*p2)=F(p1*p2)-F(p1)-F(p2)+F(1)。
这里有u(1)=1, u(p2)=-1,u(p1)=-1,u(p1*p2)=1。
如果不嫌累,你就在继续推,以下直接给出莫比乌斯函数了(要是一一列举得累死我)。
u(n) = 1 如果n=1
= (-1)^r 如果n=p1*p2*......pr,其中pi为各不相同的素数
= 0 其它
行了,莫比乌斯函数有很多性质呢。就不证明了,只给出这些性质吧。
(1)莫比乌斯函数是乘性函数
(2)设F(n)=sigma[u(d)],d|n,如果n=1,则F(n)=1,若n>1则等于0。
至于如何去验证莫比乌斯函数确实能够达到反演的大家就自己研究吧。
并且若f的和函数F是乘性的,我们可以根据莫比乌斯反演推出f也是乘性的。
好了,看看利用莫比乌斯反演公式能得到什么好玩的。
设f1(n)=n,f2(n)=1
F1(n)=sigma(f1(d)), d|n1
F2(n)=sigma(f2(d)), d|n2
那么根据反演公式有
n=sigma[u(n/d)*F1(d)]
1=sigma[u(n/d)*F2(d)]
很神奇,是吧。
还有呢
若f是欧拉函数,则f(n)=n*(sigma[u(d)/d]),d|n。
今天终于把莫比乌斯看明白了,但证明貌似还是无力。
设f(d) 表示gcd为d的倍数的数的对数
g(d)表示gcd恰好为d的数的对数
f(d) = ∑ g(n) (n % d == 0)
g(d) = ∑ mu[n / d] * f(n) (n %d == 0)
上面两个式子就是套路,没啥难的
所以 g(1) = ∑mu[n] * f(n)
求一下mu[ ],枚举一下n就可以AC了
方法一:莫比乌斯反演
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=222232;
int mu[maxn],a[maxn],prime[maxn],cnt[maxn],num[maxn];
bool vis[maxn];
int n,pnum;
void mobius(int N)
{
pnum=0;
vis[1]=mu[1]=1;
for(int i=2;i<=N;i++)
{
if(!vis[i])
{
mu[i]=-1;
prime[pnum++]=i;
}
for(int j=0;j<pnum;j++)
{
if(i*prime[j]>N)break;
vis[i*prime[j]]=1;//筛掉合数
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;//保证合数使用最小的素数筛掉的
}
mu[i*prime[j]]=-mu[i];
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
mobius(222222);
while(scanf("%d",&n)!=EOF)
{
int max1=0;
memset(num,0,sizeof(num));
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
num[a[i]]++;
max1=max(max1,a[i]);
}
for(int i=1;i<=max1;i++)
for(int j=i;j<=max1;j+=i)
cnt[i]+=num[j];
long long ans=0;
for(int i=1;i<=max1;i++)
ans+=((long long)cnt[i]*(cnt[i]-1)/2)*mu[i];
printf("%lld\n",ans);
}
return 0;
}
方法二:跟莫比乌斯阿反演差不多,只不过是把它的倍数中重复计算的去掉了
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn=222232;
int cnt[maxn],n,x,max1;
LL ans[maxn];
void solve()
{
//memset(ans,0,sizeof(ans));
for(int i=2;i<=max1;i++)
{
ans[i]=0;
for(int j=i;j<=max1;j+=i)ans[i]+=cnt[j];
}
for(int i=2;i<=max1;i++)ans[i]=ans[i]*(ans[i]-1)/2;
for(int i=max1;i>1;i--)
for(int j=2*i;j<=max1;j+=i)
ans[i]-=ans[j];//把重复计算的去掉
LL sum=0;
for(int i=2;i<=max1;i++)sum+=ans[i];
sum=(LL)n*(n-1)/2-sum;
printf("%lld\n",sum);
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(cnt,0,sizeof(cnt));
max1=0;
for(int i=0;i<n;i++)
{
scanf("%d",&x);
max1=max(max1,x);
cnt[x]++;
}
solve();
}
return 0;
}