题目大意
求 [ l , r ] [l,r] [l,r]中和 n n n互质的数的个数
解题思路
根据容斥定理问题可以转化为 [ 1 , x ] [1,x] [1,x]中和 n n n互质的个数,然后 s o l v e ( r ) − s o l v e ( l − 1 ) solve(r)-solve(l-1) solve(r)−solve(l−1)即可。但是互质的数不好求,问题又变成了求出不互质的数的个数,然后拿 n n n减去就得到了互质的个数。
x , y x,y x,y不互质等价于 g c d ( x , y ) ≠ 1 gcd(x,y) \neq 1 gcd(x,y)=1,考虑最大公约数在质因数分解下的意义,也就是考虑 n n n的每一种质数的组合,求出 n n n以内有多少个它的倍数。但是这样会重复计算。假设 n = 2 x ∗ 3 y n=2^x*3^y n=2x∗3y,我们已经统计了 n n n以内 2 2 2的倍数的个数 ⌊ n 2 ⌋ \lfloor \frac{n}{2} \rfloor ⌊2n⌋,然后再求 n n n以内 3 3 3的倍数的个数 ⌊ n 3 ⌋ \lfloor \frac{n}{3} \rfloor ⌊3n⌋,显然前者和后者有重复的统计部分,这个重复的部分就是 n n n以内 2 ∗ 3 2*3 2∗3的倍数的个数,因此我们考虑所有的组合状态,若素数种类数为奇数就加上统计的部分,否则减去统计的部分。
代码
不难得知 i n t int int范围内最多有 9 9 9种质因数,即最大且种类最多的数为 2 ∗ 3 ∗ 5 ∗ . . . ∗ 23 2*3*5*...*23 2∗3∗5∗...∗23,那么所有的状态数也只有 ( 1 < < 9 ) − 1 (1<<9)-1 (1<<9)−1种,状压枚举即可。
//
// Created by Happig on 2020/10/8
//
#include <bits/stdc++.h>
#include <unordered_map>
#include <unordered_set>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define ins insert
#define Vector Point
#define ENDL "\n"
#define lowbit(x) (x&(-x))
#define mkp(x, y) make_pair(x,y)
#define mem(a, x) memset(a,x,sizeof a);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double dinf = 1e300;
const ll INF = 1e18;
const int Mod = 1e9 + 7;
const int maxn = 2e5 + 10;
vector<ll> prime;
void init(ll n) {
prime.clear();
for (ll i = 2; i * i <= n; i++) {
if (n % i == 0) {
prime.push_back(i);
while (n % i == 0) n /= i;
}
}
if (n > 1) prime.push_back(n);
}
ll solve(ll r) {
ll ans = 0;
for (ll s = 1; s < (1 << prime.size()); s++) {
ll num = 1, cnt = 0;
for (int i = 0; i < prime.size(); i++) {
if (s & (1 << i)) {
cnt++;
num *= prime[i];
}
}
ll res = r / num;
if (cnt & 1) ans += res;
else ans -= res;
}
return r - ans;
}
int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t, kase = 0;
ll l, r, n;
cin >> t;
while (t--) {
cin >> l >> r >> n;
init(n);
cout << "Case #" << ++kase << ": " << solve(r) - solve(l - 1) << ENDL;
}
return 0;
}