POJ 3904

第一道莫比乌斯反演的题。

建议参看http://www.isnowfy.com/mobius-inversion/

摘其中部分

证明的话感觉写起来会比较诡异,大家意会吧
说一下这个经典题目:令R(M,N)=1xM,1yN中 gcd(x,y)=1 的个数
我们说G(z)表示gcd(x,y)是z的倍数的个数(以后都省略1xM,1yN的前提),换句话说z|gcd(x,y)的个数,那么很显然G(z)=M/zN/z,令F(z)表示gcd(x,y)=z的个数,

所以G(z)=(F(z)+F(2z)+F(3z)...),于是我们得到F(z)=(G(z)μ(z)+G(2z)μ(2z)...),从而得到了我们最终的答案ans=z1M/zN/zμ(z)

这里,只需要把z=1,通过求F(z)即可。

上面之所以成立,因为莫比乌斯的另一种形式(我未找到,但确实成立)

f(d) = ∑ g(n) (n % d == 0)

g(d) = ∑  mu[n / d] * f(n) (n %d == 0)

好像目前遇到的都是经典题目的类型了。。。

给出求莫比乌斯函数的代码:

void initial(){
	int i,j;
	for(i=1;i<N;i++) mobi[i]=1,vis[i]=false; 
	for(i=2;i<N;i++) {
		if(vis[i]) continue;
		for(j=i;j<N;j+=i){
			vis[j]=true;
			if((j/i)%i==0){
				mobi[j]=0; continue;
			}
			mobi[j]=-mobi[j];
		}
	}
}

  

POJ 代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 10005
#define LL __int64
using namespace std;

int ID[N];
int mobi[N],cnt[N];
bool vis[N];
LL myc[N];

void initial(){
	int i,j;
	for(i=1;i<N;i++) mobi[i]=1,vis[i]=false; 
	for(i=2;i<N;i++) {
		if(vis[i]) continue;
		for(j=i;j<N;j+=i){
			vis[j]=true;
			if((j/i)%i==0){
				mobi[j]=0; continue;
			}
			mobi[j]=-mobi[j];
		}
	}
	myc[0]=myc[1]=myc[2]=myc[3]=0;
	myc[4]=1;
	for(int i=5;i<N;i++)
	myc[i]=myc[i-1]*(LL)i/(LL)(i-4);  //这里求的其实是组合数
}

int main(){
	int n; int mx,tmp;
	initial();
	while(scanf("%d",&n)!=EOF){
		mx=-1;
		memset(ID,0,sizeof(ID));
		for(int i=0;i<n;i++){
			scanf("%d",&tmp);
			ID[tmp]++;
			mx=max(mx,tmp);
		}
		memset(cnt,0,sizeof(cnt));
		for(int i=1;i<=N;i++){
			for(int k=i;k<N;k+=i){
				if(ID[k])
				cnt[i]+=ID[k];
			}
		}
		LL ans=0;
		for(int i=1;i<=mx;i++){
			ans=ans+(LL)mobi[i]*myc[cnt[i]];
		}
		printf("%I64d
",ans);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/jie-dcai/p/4004625.html