HDU 1695 GCD(莫比乌斯反演)



题意:给定两个数,其中,求为质数的有多少对?其中的范围是

思路:莫比乌斯反演。莫比乌斯反演一般有两种形式,一般书里介绍的是第一种,

HDU 1695 GCD(莫比乌斯反演)_第1张图片

自己总结了一下,一般来说,f函数是一个很不好求的东西,F函数是一个相对好求的东西,我们通过莫比乌斯反演,将求f函数转化为求F函数的和,一般这样做可以大大加速计算过程。

回到这道题,用f(i)表示gcd为i的数对有多少,用F(i)表示gcd为i的倍数的数有多少,那么我们就得到了上图中的第二个式子,而我们要求的就是f(K)减去其中重复的数对数量,至此我们就可以轻松得到答案了。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define eps 1e-6
#define LL long long
#define pii pair
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 150000;
bool check[MAXN+10];
int prime[MAXN+10];
int mu[MAXN+10];
void Moblus()
{
    memset(check,false,sizeof(check));
    mu[1] = 1;
    int tot = 0;
    for(int i = 2; i <= MAXN; i++)
    {
        if( !check[i] )
        {
            prime[tot++] = i;
            mu[i] = -1;
        }
        for(int j = 0; j < tot; j++)
        {
            if(i * prime[j] > MAXN) break;
            check[i * prime[j]] = true;
            if( i % prime[j] == 0)
            {
                mu[i * prime[j]] = 0;
                break;
            }
            else
            {
                mu[i * prime[j]] = -mu[i];
            }
        }
    }
} 
int main() {
    //freopen("input.txt", "r", stdin);
	int a, b, c, d, k; 
	int T; cin >> T;
	int kase = 0;
	Moblus();
	while(T--) {
		scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
		if(b > d) swap(b, d);
		if(!k) {
			printf("Case %d: 0\n", ++kase);
			continue;
		}
		LL ans1 = 0, ans2 = 0;
		for(int i = k; i <= b; i+=k) {
			ans1 += (LL)mu[i/k]*(b/i)*(d/i);
			ans2 += (LL)mu[i/k]*(b/i)*(b/i);
		}
		//cout << ans1 << endl << ans2 << endl;
		printf("Case %d: %I64d\n", ++kase, ans1-(ans2-1)/2);	
	}
    return 0;
}

















你可能感兴趣的:(程序设计竞赛)