给定b,d,k,[1,b],[1,d]中取x,y,求gcd(x,y) = k的(x,y)对数
ps:(1,2)和(2,1)相同
简化为gcd(x / k,y / k) = 1
gcd(x,y) = 1,x,y范围为[1,b / k],[1,d / k]
1.欧拉函数+容斥
2.莫比乌斯
大佬题解
https://www.cnblogs.com/iiyiyi/p/5635303.html
1.欧拉函数+容斥
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 1e5 + 5;
typedef long long ll;
int a,b,c,d,k;
ll phi[maxn];
int fac[15],num = 0;
void init()
{
for (int i = 2; i < maxn; i ++) {
if(phi[i] == 0){
for (int j = i; j < maxn; j += i) {
if(phi[j] == 0) phi[j] = j;
phi[j] = phi[j] / i * (i - 1);
}
}
}
phi[1] = 1;
for (int i = 2; i < maxn; i ++) {
phi[i] += phi[i - 1];
}
}
void divide(int y)
{
num = 0;
for (int i = 2; i <= sqrt(0.5 + y); i ++) {
if(y % i == 0){
fac[num ++] = i;
while(y % i == 0) y/= i;
}
}
if(y > 1) fac[num++] = y;
}
ll solve(int b)//质因子分解可以打表
{
ll ans = 0;
for (int i = 1; i < (1 << num); i ++) {
int t = i,cnt = 0;
ll lcm = 1;
for (int j = 0; j < num; j ++) {
if(t & 1){lcm *= fac[j];cnt ++;}
t >>= 1;
if(t == 0) break;
}
if(cnt & 1) ans += b / lcm;
else ans -= b / lcm;
}
return ans;
}
int main()
{
init();
int T;scanf("%d",&T);
for (int cn = 1; cn <= T; cn ++) {
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
//k = 0?
if(k == 0){ printf("Case %d: 0\n",cn);continue;}
b /= k;d /= k;
if(b > d) swap(b, d);
ll ans = phi[b];
//[b + 1,d]
for (int i = b + 1; i <= d; i ++) {
divide(i);
ans += b- solve(b);
}
printf("Case %d: %lld\n",cn,ans);
}
return 0;
}
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
int mo[maxn];
bool isprime[maxn];
int prime[maxn / 10],sz = 0;
int a,b,c,d,k;
void init()
{
for (int i = 2; i < maxn; i ++) {
if(isprime[i] == 0){
prime[sz ++] = i;
mo[i] = -1;
}
for (int j = 0; j < sz && prime[j] * i < maxn; j ++) {
isprime[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
else mo[i * prime[j]] = -mo[i];
}
}
mo[1] = 1;
}
int main()
{
init();
int T;scanf("%d",&T);
for (int cn = 1; cn <= T; cn ++) {
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if(k == 0){printf("Case %d: 0\n",cn);continue;}
b /= k;d /= k;
int t = min(b,d);
ll ans1 = 0,ans2 = 0;
for (int i = 1; i <= t; i ++) {
ans1 += (ll)mo[i] * (b / i) * (d / i);
}
for (int i = 1; i <= t; i ++) {
ans2 += (ll)mo[i] * (t / i) * (t / i);
}
printf("Case %d: %lld\n",cn,ans1 - ans2 / 2);
}
return 0;
}