HDU 1695:GCD(莫比乌斯反演)

给你 a , b , c , d , k 五个值 (题目说明了 你可以认为 a=c=1) ,所以 x 属于 [1,b] ,y属于[1,d] 让你求有多少对这样的 (x,y)满足gcd(x,y)==k。

首先 ,这道题可以进行简化,因为 gcd(x,y)=k, 那么,很显然 gcd(x / k,y / k)是等于 1 的。那么,此时问题就可以转化为: x 属于 [1,b / k] ,y属于[1,d / k] ,让你求有多少对这样的 (x,y)满足gcd(x,y)== 1 ,即x和y是互质的。 我们需要用到莫比乌斯反演(当然容斥定理也可以),先来看一下什么是莫比乌斯反演。

这里先给出莫比乌斯的两个公式 :
这里写图片描述
这里写图片描述

这两个就是莫比乌斯反演的两种表现形式
反演的核心所在是莫比乌斯函数,什么是莫比乌斯函数呢? 我们在下面给出它的定义:

这里写图片描述

它就是莫比乌斯函数,我们称之为 mu 函数,也是整个反演最为重要的部分。

现在我们来继续解决上面的那个问题。如何去求有多少对这样的 (x,y)满足gcd(x,y)== 1 。这个问题你直接拿到手发现确实比较麻烦,但是换个思路,如果我们去求有多少对这样的 (x,y)满足 gcd(x,y)== 1 的倍数 呢? 是不是就非常简单了呢?

我们设:

F[i] 为有多少对(x,y)满足 gcd(x,y)== i 的倍数
f[i] 为有多少对(x,y)满足 gcd(x,y)== i

F[i] 很容易求出是 F[i]=b/i*d/i

所以我们需要解决的问题,就是如何求出 f[1]

根据这里写图片描述公式你可以发现,在你对函数进行构造时是需要满足反演对函数的要求的,这个需要你自己来体会,至于另一个公式的构造方法是 “约数” 的关系,而这个则是 “倍数” 的关系。
我们很容易得到 F[i]=f[i] + f[i2] + f[i3]+…
根据公式我们也很容易得到 f[1]= mu[1]*F[1]+ mu[2]*F[2]+……

我们在对[1,b/k]和[1,d/k]这两个区间求有多少对(x,y)满足gcd(x,y)=1的时候,实际上有重复的情况
因为(x,y)是无序的,在[1,min(b/k,d/k)]区间上,我们实际上计算了两次,所以我们还需要减去多的一次,具体看代码。
还有就是 k 可能为0,记得特判一下
代码:

#include
#include
using namespace std;

typedef long long ll;
const int maxn=100000+100;

int mu[maxn];
bool isprime[maxn];
int prime[maxn],tot;

void init(){
	
	for(int i=0;id) swap(b,d);
		printf("Case %d: %lld\n",++C,Mobius(b,d));
	}
}

你可能感兴趣的:(HDU,ACM)