SPOJ-PGCD Primes in GCD Table
题目链接:https://vjudge.net/problem/SPOJ-PGCD
题目大意:
给定 \(N\) 和 \(M\),求满足 \((1 \le x \le N), (1 \le y \le M)\),且 \(gcd(x,y)\) 为素数的 \((x,y)\) 的对数。
知识点: 莫比乌斯反演
解题思路:
设 \(g(p)\) 表示满足 \((1 \le x \le N), (1 \le y \le M)\),且 \(gcd(x,y) = p\) 的 \((x,y)\) 的对数。直接求 \(g(p)\) 是不可行的,其时间复杂度为 \(O(NM)\).
再设 \(f(p)\) 表示满足 \((1 \le x \le N), (1 \le y \le M)\),且 \(p|gcd(x,y)\) 的 \((x,y)\) 的对数,易知 \(f(p)=(N/p)*(M/p)\)。且不难推出 \(f(n) = \sum \limits_{n|d} g(d)\). \((1)\)
莫比乌斯反演公式:若满足 \(F(n) = \sum \limits_{n|d} f(d)\),则有 \(f(n) = \sum \limits_{n|d} \mu(\frac{d}{n})F(d)\).
将其代入式 \((1)\) 得:
\(g(n) = \sum \limits_{n|d} \mu(\frac{d}{n})f(d) = \sum \limits_{n|d} \mu(\frac{d}{n})(N/d)(M/d)\) \((2)\)
最终的答案为(\(p\) 代表质数):
\(\sum \limits_{p} g(p) = \sum \limits_{p} \sum \limits_{p|d} \mu(\frac{d}{p})(N/d)(M/d)\)
\(= \sum \limits_{d}^{min(M,N)} (N/d)(M/d) \sum \limits_{p|d} \mu(\frac{d}{p})\) \((3)\)
第二个求和函数可以预处理,枚举每一个质数,更新对应的前缀和。
AC代码:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 typedef long long LL; 5 const int maxn = 1e7+5; 6 bool check[maxn]; 7 int prime[maxn],Mobius[maxn]; 8 int tot; 9 int u[maxn]; 10 11 void init(){ 12 Mobius[1]=1; 13 tot=0; 14 for(int i=2;i<maxn;i++){ 15 if(!check[i]){ 16 prime[tot++]=i; 17 Mobius[i]=-1; 18 } 19 for(int j=0;j<tot&&i*prime[j]<maxn;j++){ 20 check[i*prime[j]]=true; 21 if(i%prime[j]==0){ 22 Mobius[i*prime[j]]=0; 23 break; 24 } else 25 Mobius[i*prime[j]]=-Mobius[i]; 26 } 27 } 28 for(int i=0;i<tot;i++){ 29 for(int j=prime[i];j<maxn;j+=prime[i]){ 30 u[j]+=Mobius[j/prime[i]]; // u[j] 代表分子为 j(对应式3中的d) 的和函数的值 31 } 32 } 33 for(int i=1;i<maxn;i++) u[i]+=u[i-1]; //处理出前缀和 34 } 35 int main(){ 36 init(); 37 int t,n,m; 38 scanf("%d",&t); 39 while(t--){ 40 LL ans=0; 41 int last; 42 scanf("%d%d",&n,&m); 43 for(int i=1;i<=min(n,m);i=last+1){ 44 last=min(n/(n/i),m/(m/i)); // [i,last] 这一段的 u[] 对应 (N/d)(M/d) 相等,不难用实验验证 45 ans+=(LL)(n/i)*(m/i)*(u[last]-u[i-1]); 46 } 47 printf("%lld\n",ans); 48 } 49 return 0; 50 }