入门级别的题(不过貌似我一开始想复杂了
题目链接
题目描述
给定 $N, M$,求 $1 \leq x \leq N$,$1 \leq y \leq M$ 且 $\gcd(x, y)$ 为质数的 $(x, y)$ 有多少对。
题解
直接上柿子
如果莫比乌斯反演做了个几道题,就会知道要化简后面那个式子
我们令$f(k)=\sum_{i=1}^{N}\sum_{j=1}^{M}[gcd(i,j)==k],F(k)=\sum_{i=1}^{N}\sum_{j=1}^{M}[k|gcd(i,j)]$
然后可以得到
代入到 Ans 中,可以得到
这题因为是多组询问,如果我们将$\lfloor\frac{N}{d}\rfloor\lfloor\frac{M}{d}\rfloor$放在内层的话不好进行整数分块,因此要想办法将其放到外层
因此我们外层枚举 d :
内层的这个与 N 和 M 无关,因此是可以预处理出其前缀和的,之后就可以进行整除分块了。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include <bits/stdc++.h> using namespace std; const int N=1e7+10,M=1e6+10; int mu[N],prime[M]; bool f[N]; long long sum[N]; inline void init(){ f[1]=true,mu[1]=1; int maxn=1e7; for(int i=2;i<=maxn;++i){ if(!f[i]){ prime[++prime[0]]=i; mu[i]=-1; } for(int j=1;j<=prime[0]&&i*prime[j]<=maxn;++j){ f[i*prime[j]]=true; if(i%prime[j]==0)break; mu[i*prime[j]]=-mu[i]; } } for(int j=1;j<=prime[0];++j) for(int i=1;i*prime[j]<=maxn;++i) sum[i*prime[j]]+=mu[i]; for(int i=1;i<=maxn;++i) sum[i]+=sum[i-1]; }inline long long F(int n,int m){ int maxn=min(n,m); long long ans=0; for(int l=1,r=1;l<=maxn;l=r+1){ r=min(n/(n/l),m/(m/l)); ans+=(sum[r]-sum[l-1])*(n/l)*(m/l); }return ans; } int main(){ int T,n,m; init(); scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); printf("%lld\n",F(n,m)); } return 0; }
|