概况
两种形式
这一种用的比较多 (公式1)
另外一种 (公式2)
一般来说 我们转化时候的f(n)都比较好求,有的用公式就可以直接写出
比如下面的hdu1695
基本的代码(莫比乌斯函数的求法)
通过积性函数筛来解决
void Prime(int n)
{
int cnt=0;
memset(vis,0,sizeof(vis));
memset(mu,0,sizeof(mu));
mu[1]=1;
for(int i=2;i<n;i++) {
if(!vis[i]) {
prime[cnt++]=i;
mu[i]=-1;
}
for(int j=0;j<cnt&&i*prime[j]<n;j++) {
ll k=i*prime[j];
vis[k]=1;
if(i%prime[j]==0) {
mu[k]= 0;
break;
}
else mu[k]=-mu[i];
}
}
}
//在主程序中这样调用 算出1-n的莫比乌斯函数
Prime(MAXN);
典型题目
hdu1695
g[i]表示gcd(x,y)=i的对数,x取值范围[1..ra],y取值范围[1..rb];
给你k,让你求g[k]
则f[i]表示gcd(x,y)=i,2i,3i....的对数,由乘法原理知道f[i]=(ra/i)*(rb/i)
则用反演公式1
可以求出g(k)
设p=min(ra,rb);
去重的话要减掉[1..p]中gcd(x,y)=i的个数,设其为extra(这个也要用莫比乌斯反演求)
则答案=g[k]-extra/2;
下面上代码
#include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
const int MAXN=1000005;
bool vis[MAXN];
ll mu[MAXN];
int i,n,T;
ll prime[MAXN];
ll f[MAXN];
ll la,lb,ra,rb,k,p,ans,d,extra;
void Prime(int n)
{
int cnt=0;
memset(vis,0,sizeof(vis));
memset(mu,0,sizeof(mu));
mu[1]=1;
for(int i=2;i<n;i++) {
if(!vis[i]) {
prime[cnt++]=i;
mu[i]=-1;
}
for(int j=0;j<cnt&&i*prime[j]<n;j++) {
ll k=i*prime[j];
vis[k]=1;
if(i%prime[j]==0) {
mu[k]= 0;
break;
}
else mu[k]=-mu[i];
}
}
}
int main() {
Prime(MAXN-5);
cin>>T;
for (int tt=1; tt<=T; tt++) {
scanf("%lld%lld%lld%lld%lld",&la,&ra,&lb,&rb,&k);
if (k==0) {
cout<<"Case "<<tt<<": "<<0<<endl;
continue;
}
p=min(ra,rb);
for (i=1; i<=p; i++) f[i]=(ra/i)*(rb/i);
ans=0; extra=0;
for (d=k; d<=p; d+=k) ans+=mu[d/k]*f[d];
for (d=k; d<=p; d+=k) extra+=mu[d/k]*(p/d)*(p/d);
cout<<"Case "<<tt<<": "<<ans-extra/2<<endl;
}
return 0;
}
// 这题要去重复