Description
求出给定区间 [A,B] 中与 N 互质的数的个数。
其中, \(1\leq A,B\leq10^{15}\) ,\(1\leq N\leq10^9\)。
Solution
这种区间查询操作容易转化成前缀相减操作。
设 \(\operatorname{Ans[A]}\) 表示 \(\operatorname{[1,A] }\) 中与 N 互质的个数,\(\operatorname{Ans[B-1]}\) 表示 \(\operatorname{[1,B-1] }\) 中与 N 互质的个数。
答案就是 \(\operatorname{Ans[A]}-\) \(\operatorname{Ans[B-1]}\)。
那么问题就转化为了求 \(\operatorname{[1,M]}\) 中与 N 互质的个数。此时就不能从欧拉函数来考虑。
考虑容斥,因为与 N 互质的数 X,\(\operatorname{(X,N)}=1\),两者不含相同因子。
由唯一分解定理可知,设 X=\(\sum_{i=1}^np_i^{k_i}\) (\(p_i\) 表示质因数)。
设其中与 N 重复的质因数有 \(p_i\),\(p_j\),\(p_k\)...\(p_m\)。
由容斥定理可得:
\(\operatorname{Ans[i]}\)=\(m\) \(-\) \(\sum_{i=1}^m\lfloor \frac{N}{p_i} \rfloor\) \(+\) \(\sum_{i=1}^m\sum_{j=i+1}^m\lfloor \frac{N}{p_ip_j} \rfloor\)...
因为 N 的质因子个数不超过 \(\log(N)\) 个,所以枚举的时间复杂度小于 \(\omicron(\sqrt N)\)。
总时间复杂度:\(\omicron(T\sqrt N)\)。
Code:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN=1e6;
#define int long long
int t,a,b,n,cnt,k,mp[MAXN+5],p[MAXN+5],ans[MAXN+5],num[MAXN+5],phi[MAXN+5],sum[MAXN+5],v[MAXN+5],tot,pp;
bool vis[MAXN+5];
void Work(int x)
{
tot=0;
for(int i=2;i*i<=x;i++)
{
if(x%i==0)
{
v[++tot]=i;
while(x%i==0)
{
x/=i;
}
}
}
if(x!=1)
{
v[++tot]=x;
}
}
void dfs(int now,int &V,int res,int up,int cc)
{
if(now>tot)
{
if(!cc)
{
return;
}
if(cc&1)
{
V-=up/res;
}
else{
V+=up/res;
}
return;
}
dfs(now+1,V,res*v[now],up,cc+1);
dfs(now+1,V,res,up,cc);
}
int Ans(int x)
{
if(!x)
{
return 0;
}
int val=x,cc=0;
dfs(1,val,1,x,cc);
return val;
}
signed main()
{
scanf("%lld",&t);
while(t--){
scanf("%lld%lld%lld",&a,&b,&n);
Work(n);
printf("Case #%lld: %lld\n",++pp,Ans(b)-Ans(a-1));
}
return 0;
}
\(\Bbb{End.}\)
\(\Bbb{Thanks}\) \(\Bbb{For}\) \(\Bbb{Reading.}\)