Solution [POI2007]ZAP-Queries
题目大意:多组数据,每次给定(a,b,d),询问(sum_{i=1}^{a}sum_{j=1}^{b}[gcd(i,j)=d])
莫比乌斯反演
解析:
[egin{aligned}ans &= sum_{i=1}^{a}sum_{j=1}^{b}[gcd(i,j)=d] \ &=sum_{i=1}^{lfloor frac{a}{d}
floor}sum_{j=1}^{lfloor frac{b}{d}
floor}[gcd(i,j)=1]end{aligned}
]
方便起见,令(n=lfloor frac{a}{d} floor),(m=lfloor frac{b}{d} floor)
[egin{aligned}ans &= sum_{i=1}^{n}sum_{j=1}^{m}[gcd(i,j)=1] \ &= sum_{i=1}^{n}sum_{j=1}^{m}epsilon(gcd(i,j))end{aligned}
]
因为(mu * 1=epsilon),且(d mid gcd(i,j) Longleftrightarrow dmid i,d mid j)
[egin{aligned}ans &= sum_{i=1}^{n}sum_{j=1}^{m}sum_{dmid i,d mid j}mu(d) \ &= sum_{d=1}^{min(n,m)}mu(d)sum_{i=1}^{n}sum_{j=1}^{m}[d mid i][d mid j] \ &= sum_{d=1}^{min(n,m)}mu(d)lfloorfrac{n}{d}
floorlfloorfrac{m}{d}
floor end{aligned}
]
筛出(mu),整除分块求解即可
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
const int maxn = 1e5;
int vis[maxn],mu[maxn];
inline int sum(int a,int b){return mu[b] - mu[a - 1];}
vector<int> pri;
inline void sieve(){
mu[1] = 1;
for(int i = 2;i < maxn;i++){
if(!vis[i]){
pri.push_back(i);
mu[i] = -1;
}
for(int x : pri){
if(1ll * x * i >= maxn)break;
vis[i * x] = 1;
if(i % x){
mu[i * x] = mu[i] * mu[x];
}else{
mu[i * x] = 0;
break;
}
}
}
for(int i = 1;i < maxn;i++)mu[i] += mu[i - 1];
}
int t,a,b,n,m,d;
inline void solve(){
cin >> a >> b >> d;
n = a / d,m = b / d;
int ans = 0;
for(int l = 1,r;l <= min(n,m);l = r + 1){
r = min(n / (n / l),m / (m / l));
ans += sum(l,r) * (n / l) * (m / l);
}
cout << ans << '
';
}
int main(){
sieve();
cin >> t;
while(t--)solve();
return 0;
}