题意:给定两个数和,其中,,求为质数的有多少对?其中和的范围是。
思路:莫比乌斯反演。莫比乌斯反演一般有两种形式,一般书里介绍的是第一种,
自己总结了一下,一般来说,f函数是一个很不好求的东西,F函数是一个相对好求的东西,我们通过莫比乌斯反演,将求f函数转化为求F函数的和,一般这样做可以大大加速计算过程。
回到这道题,用f(i)表示gcd为i的数对有多少,用F(i)表示gcd为i的倍数的数有多少,那么我们就得到了上图中的第二个式子,而我们要求的就是f(K)减去其中重复的数对数量,至此我们就可以轻松得到答案了。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#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;
}