题意:
给你两个区间
和
,再给你一个
,默认
(那为什么还给a,b,直接给b,d不就好了吗,专门坑我这种读题不仔细的人…),然后问你
,其中
有多少对。(3,5)和(5,3)是一种。
思路
让求
,转换一下即求
,不就是求两个区间互质的有多少对嘛,直接上容斥,等等…结果不大对,唔,(3,5)和(5,3)算一种,那可怎么办才好,得不重不漏才行呐,看别人题解恍然大悟(莫比乌斯滚蛋)。
对于
(假设b<=d) ,我们可以将大区间 分为两个部分即
对于[1,b]和[1,b]求互质对,就是求
(想想是不是)
对于[1,b]和[b+1,d]这一部分用容斥直接算就行,不会产生重复对。
妙哉!
#include <iostream>
#include <cstring>
#include <queue>
#include <cmath>
#include <map>
#include<vector>
#include <stack>
#include <cstdio>
#include <sstream>
#include <algorithm>
using namespace std;
#define read(x) scanf("%d", &x)
#define Read(x, y) scanf("%d%d", &x, &y)
#define gc(x) scanf(" %c", &x);
#define mmt(x, y) memset(x, y, sizeof x)
#define write(x) prllf("%d\n", x)
#define INF 0x3f3f3f3f
#define ll long long
#define mod 998244353
const ll N = 1e5 + 5;
ll m , n;
vector<ll> fac[N+1000];
bool vis[N+1000];
void prime(){
vis[1] = 1;
for(ll i = 2;i <= N;++i)if(!vis[i]){
fac[i].push_back(i);
for(ll j = i + i;j <= N;j += i) {vis[j] = 1;fac[j].push_back(i);}
}
}
int phi[N + 1000], prime1[N + 1000];
int tot;//tot计数,表示prime1[N]中有多少质数
void Euler(){
phi[1] = 1;
for(int i = 2; i < N; i ++){
if(!phi[i]){
phi[i] = i-1;
prime1[tot ++] = i;
}
for(int j = 0; j < tot && 1ll*i*prime1[j] < N; j ++){
if(i % prime1[j]) phi[i * prime1[j]] = phi[i] * (prime1[j]-1);
else{
phi[i * prime1[j] ] = phi[i] * prime1[j];
break;
}
}
}
}
int solve(ll n){
ll ans = 0;
//if(n == 1) {ans += m;return ;}
ll k = fac[n].size();
ll s = 1<<k;
for(ll i = 1;i < s;++i){
ll cnt = 0;
ll p = 1;
for(ll j = 0;j < k;++j ){
if((i >> j) & 1) {cnt ++;p *= fac[n][j];}
}
if(cnt & 1) ans += m/p;
else ans -= m/p;
}
return m - ans;
}
int main(){
ll t;
ll a,b,c,d;
ll k;
prime();
Euler();
cin >> t;
for(int Case = 1;Case <= t;Case ++ ){
cin >> a >> b >> c >> d >> k;
if(k == 0) {printf("Case %d: %lld\n",Case,0);continue;}
n = b,m = d;
n /= k;m /= k;
if(m > n) swap(n,m);
ll ans = 0;
for(ll i = m + 1;i <= n;++i){
ans += solve(i) ;
}
for(int i = 1;i <= m;++i) ans += phi[i];
printf("Case %d: %lld\n",Case,ans);
}
}