题意:\(x\sqsubseteq [1,b]\),\(y\sqsubseteq [1,d]\) ,求\(gcd(x,y)=k\)的\((x,y)\)的个数
分析:显然,等价于求\(b,d\)同时除以\(k\),求\(gcd(x',y')=1\)的个数,因为\((1,3)\)和\((3,1)\)是一种情况,所以要限制\((x<y)\)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
//返回1-m中与n互素的数的个数
vector<LL> p;
LL cal(LL n, LL m) {
p.clear();
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
p.push_back(i);
while (n % i == 0) n /= i;
}
}
if (n > 1) p.push_back(n); //求n的素因子
LL s = 0; // 1到m中与n不互素的数的个数
//枚举子集,不能有空集,所以从1开始
for (LL i = 1; i < 1 << p.size(); i++) { //从1枚举到(2^素因子个数)
LL cnt = 0;
LL t = 1;
for (LL j = 0; j < p.size(); j++) { //枚举每个素因子
if (i & (1 << j)) { //有第i个因子
cnt++; //计数
t *= p[j]; //乘上这个质因子
}
}
//容斥原理
if (cnt & 1) //选取个数为奇数,加
s += m / t;
else //选取个数为偶数,减
s -= m / t;
}
return m - s; //返回1-m中与n互素的数的个数
}
int main() {
int T, ca = 0;
scanf("%d", &T);
while (T--) {
LL a, b, c, d, k;
scanf("%lld%lld%lld%lld%lld", &a, &b, &c, &d, &k);
// k=0时需要特判,因为我们想要 x'=x/k ,y'=y/k,不能随意随,需要判断
if (!k) {
printf("Case %d: 0\n", ++ca);
continue;
}
b /= k, d /= k;
//因为 (1,3)与 (3,1)算1个,所以要限制x<y
if (b > d) swap(d, b);
LL ans = 0;
for (LL i = 1; i <= d; i++) //只算小区间
ans += cal(i, min(i, b)); //求区间[1,b]内与i互质的个数
printf("Case %d: %lld\n", ++ca, ans);
}
return 0;
}