题意:
给出 l,r,n ,询问 [l,r] 与 n 互质的数的个数
询问共T 组,保证 0<T≤100,1≤n≤109,1≤l,r≤1015
solution:
用 r 的前缀和减去
l−1 的前缀和,将 n 暴力质因数分解
枚举n 的质因子集合,每次统计有多少数字是子集乘积的倍数
这个东西用容斥原理直接算一下就好了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = 32000;
typedef long long LL;
int T,n,tot,tp,pri[maxn],stk[maxn];
bool not_pri[maxn]; LL l,r;
LL Calc(LL k)
{
LL ret = k;
for (int o = 1; o < (1 << tp); o++)
{
LL sum,tmp; sum = tmp = 1;
for (int j = 0; j < tp; j++)
if (o & (1 << j)) sum *= stk[j],tmp *= -1;
ret += tmp * (k / sum);
}
return ret;
}
void Solve(int I)
{
scanf("%lld%lld%d",&l,&r,&n);
for (int i = 1; i <= tot; i++)
{
if (n % pri[i] != 0) continue;
stk[tp++] = pri[i];
while (n % pri[i] == 0) n /= pri[i];
if (n == 1) break;
}
if (n > 1) stk[tp++] = n;
LL Ans = Calc(r);
if (l > 1) Ans -= Calc(l - 1);
printf("Case #%d: %lld\n",I,Ans); tp = 0;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
for (int i = 2; i < maxn; i++)
{
if (!not_pri[i]) pri[++tot] = i;
for (int j = 1; j <= tot; j++)
{
int Nex = pri[j] * i;
if (Nex >= maxn) break;
not_pri[Nex] = 1;
if (i % pri[j] == 0) break;
}
}
cin >> T;
for (int i = 1; i <= T; i++) Solve(i);
return 0;
}