P3455 [POI2007]ZAP-Queris(莫比烏斯反演)
阿新 • • 發佈:2021-07-12
題意:
給出\(a,b,d\),求滿足\(1 \leq x \leq a,1 \leq y \leq b\),且\(gcd(x,y)=d\)的二元組\((x,y)\)的數量。
\(1 \leq n \leq 5 \times 10^4\)
\(1 \leq d \leq a,b \leq 5 \times 10^4\)
題解:
寫出式子:
\(\sum_{i=1}^a\sum_{j=1}^b[gcd(i,j)=k]\)
可以把\(d\)提取出來,變成
\(\sum_{i=1}^{a/k}\sum_{i=1}^{b/k}[gcd(i,j)=1]\)
可以把\(gcd(i,j)=1\)變成\(\sum_{d|gcd(i,j)}\mu(d)\)
\(\sum_{i=1}^{a/k}\sum_{j=1}^{b/k}\sum_{d|gcd(i,j)}\mu(d)\)
即\(i,j\)都是\(d\)的倍數,且\(d\)的範圍一定是\(min(a,b)\)。
這裡預設\(a\)是較小的那個,
所以可以把\(d\)移到前面,變成
\(\sum_{d=1}^a\mu(d)[n/kd][m/kd]\)
然後套一個二維的數論分塊,時間複雜度\(O(\sqrt{n})\)。
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+100; typedef long long ll; int vis[maxn]; ll pri[maxn],mu[maxn],sum[maxn],cnt; void getMu (ll n) { //線性篩莫比烏斯函式,並求解字首和 mu[1]=1; for (ll i=2;i<=n;i++) { if (!vis[i]) { mu[i]=-1; pri[++cnt]=i; } for (ll j=1;j<=cnt&&i*pri[j]<=n;j++) { vis[i*pri[j]]=1; if (i%pri[j]==0) break; else mu[i*pri[j]]=-mu[i]; } } for (ll i=1;i<=n;i++) sum[i]=sum[i-1]+mu[i]; } int main () { int _; scanf("%d",&_); getMu(60000); while (_--) { ll A,B,D; scanf("%lld%lld%lld",&A,&B,&D); if (A>B) swap(A,B); ll ans=0; for (ll l=1,r;l<=A;l=r+1) { r=min(A/(A/l),B/(B/l)); ans+=(A/(l*D))*(B/(l*D))*(sum[r]-sum[l-1]); } printf("%lld\n",ans); } }