题目大意
求 p∈primes∑x=1∑ny=1∑m[gcd(x,y)=p]。
T 组数据。
其中 1≤T≤10,1≤n,m≤107。
解题思路
求:
p∈primes∑x=1∑ny=1∑m[gcd(x,y)=p]
化简得:
p∈primes∑x=1∑⌊pn⌋y=1∑⌊pm⌋[gcd(x,y)=1]
根据:
d∣n∑μ(d)={10n=1n=1
有:
p∈primes∑x=1∑⌊pn⌋y=1∑⌊pm⌋k∣i,k∣j∑μ(k)
先枚举 k,有:
p∈primes∑k=1∑min(⌊pn⌋,⌊pm⌋)x=1∑⌊pn⌋y=1∑⌊pm⌋μ(k)[k∣i][k∣j]
那么就有:
p∈primes∑k=1∑min(⌊pn⌋,⌊pm⌋)⌊pkn⌋⌊pkm⌋μ(k)
设 T=pk,有:
T=1∑min(n,m)⌊Tn⌋⌊Tm⌋p∈primes,p∣T∑μ(pT)
求前缀和再数论分块即可。
CODE
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int _ = 1e7;
int T, n, m;
bool vis[_ + 7];
int tot, pri[_ + 7], g[_ + 7], sum[_ + 7], mu[_ + 7];
void init()
{
mu[1] = 1;
for(int i = 2; i < _; ++i)
{
if(!vis[i])
{
pri[++tot] = i;
mu[i] = -1;
g[i] = 1;
}
for(int j = 1; j <= tot, i * pri[j] < _; ++j)
{
vis[i * pri[j]] = 1;
if(i % pri[j])
{
mu[i * pri[j]] = -mu[i];
g[i * pri[j]] = mu[i] - g[i];
}
else
{
mu[i * pri[j]] = 0;
g[i * pri[j]] = mu[i];
break;
}
}
sum[i] = sum[i - 1] + g[i];
}
}
signed main()
{
init();
scanf("%lld", &T);
while(T--)
{
scanf("%lld%lld", &n, &m);
if(n > m) swap(n, m);
int ans = 0ll;
for(int i = 1, last; i <= n; i = last + 1)
{
last = min(n / (n / i), m / (m / i));
ans += (n / i) * (m / i) * (sum[last] - sum[i - 1]);
}
printf("%lld\n", ans);
}
return 0;
}