给两个值r, n(r <= n)求1到r中与n互质的数.用容斥原理, 假如n的素因子小于等于r的有p1, p2, p3.那么在1到r中与n互质的数的个数 = r - r / p1 - r / p2 - r / p3 + r / (p1 p2 ) + r / (p1 p3) + r / (p2 * p3) - r / (p1 * p2 * p3).这里采用了二进制枚举.
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <cstdio>
#include <queue>
#define INF 1e9
#define maxn 10000
using namespace std;
typedef long long ll;
ll solve(int r, int n){
vector<int> v;
int p = n;
for(int i = 2; i * i <= p && i <= r; i++){
if(p % i == 0){
v.push_back(i);
while(p % i == 0)
p /= i;
}
}
if(p > 1 && p <= r)
v.push_back(p);
ll sum = 0, h = 1 << v.size();
for(ll i = 1; i < h; i++){
ll cnt = 0, k = 1;
for(ll j = 0; (1<<j) <= i; j++){
if((1<<j) & i){
k *= v[j];
cnt++;
}
}
if(cnt&1)
sum -= r / k;
else
sum += r / k;
}
return r + sum;
}
int main(){
// freopen("in.txt", "r", stdin);
int t, cas = 0;
cin >> t;
while(t--){
int a, b, c, d, k;
ll sum = 0;
scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
if(k == 0 || b < k || d < k){
printf("Case %d: %d\n", ++cas, 0);
continue;
}
int k1 = b / k;
int k2 = d / k;
if(k1 > k2)
swap(k1, k2);
for(int i = 1; i <= k2; i++){
if(i <= k1)
sum += solve(i, i);
else
sum += solve(k1, i);
}
printf("Case %d: %lld\n", ++cas, sum);
}
return 0;
}