莫比乌斯反演

概况

两种形式

这一种用的比较多 (公式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;
}

// 这题要去重复 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值