题目分析
求A和B之间与N互质的数的个数,直接求显然是不行的,因为A,B非常大,但是我们回头一看会发现N很小,是不是有点想法了,是的,我们可以找到N的所有素因子,我们还可以将A,B之间与N互斥的个数转化为(1,B)-(1,A-1);这样我们就可以用容斥原理来求,我们求出(1,x)与n的每个素因子y不互斥的数的个数很明显就是x/y,运用容斥原理奇加偶减的规律,因为素因子的个数不会超过15,因此我们就可以利用状态压缩,然后这样就可以完成计算了,具体看代码。
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
#define pb push_back
vector <LL> vec;
LL solve(LL x,LL n){
vec.clear();
for(LL i = 2; i*i <= n; i++){ //求出n的所有素因子
if(n%i == 0){
vec.pb(i);
while(n%i == 0) n /= i;
}
}
if(n > 1) vec.pb(n);
LL sum = 0; //表示与(1~m)中与n不互素的数的个数
LL val, cnt;
for(LL i = 1; i < (1<<vec.size()); i++){ //容斥原理
val = 1, cnt = 0;
for(LL j = 0; j < vec.size(); j++){ //判断有多少个素因子
if(i&(1<<j)){
val *= vec[j];
cnt++;
}
}
if(cnt&1) sum += x/val; //奇加偶减
else sum -= x/val;
}
return x-sum;
}
int main(){
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif // LOCAL
int T;
LL a,b,n;
scanf("%d", &T);
for(int kase = 1; kase <= T; kase++){
scanf("%I64d%I64d%I64d", &a, &b, &n);
LL ans = solve(b,n) - solve(a-1, n);
printf("Case #%d: %I64d\n", kase, ans);
}
return 0;
}