题目链接
题意
求
∑i=1a∑j=1bf(gcd(i,j))
其中
f(x)={α1,x=p1α1∗p2α2+...+pnαn,α1>α2,...,αn0,x=1
推导
法一:艾弗森约定
记
gcd(i,j)=k
, 则有
gcd(ik,jk)=1
,
故原式可化为
∑k=1min(a,b)∑i=1⌊ak⌋∑j=1⌊bk⌋f(k)[gcd(i,j)=1]
用莫比乌斯函数将艾弗森约定展开得
∑k=1min(a,b)f(k)∑i=1⌊ak⌋∑j=1⌊bk⌋∑d|i,d|jμ(d)
即
∑k=1min(a,b)f(k)∑d=1min(⌊ak⌋,⌊bk⌋)μ(d)∑i=1⌊akd⌋∑j=1⌊bkd⌋
即
∑k=1min(a,b)f(k)∑d=1min(⌊ak⌋,⌊bk⌋)μ(d)⌊akd⌋⌊bkd⌋
令 T=kd , 得
∑T=1min(a,b)⌊aT⌋⌊bT⌋∑d|Tf(Td)μ(d)
显然,接下来的路子就是求前缀和,然后分块计算,然而 关键问题 就是怎么求这个
∑d|Tf(Td)μ(d)
呢?
参考PoPoQQQ可知,对于
g(T)=∑d|Tf(Td)μ(d),T=p1α1∗p2α2∗...∗pnαn
有
g(T)={0,∃αi≠αj,(−1)(n+1),otherwise
具体证明见上附链接,要点为从 k 个元素中选取奇数个元素的种数
法二:莫比乌斯反演(待补)
Code
#include <bits/stdc++.h>
#define maxn 10000000
#define maxm maxn + 10
using namespace std;
typedef long long LL;
bool check[maxm];
int prime[maxm], cnt[maxm], val[maxm], g[maxm], sum[maxm];
void init() {
int tot = 0; g[1] = 0;
for (int i = 2; i <= maxn; ++i) {
if (!check[i]) {
prime[tot++] = i;
cnt[i] = 1, val[i] = i, g[i] = 1;
}
for (int j = 0; j < tot; ++j) {
if (i * prime[j] > maxn) break;
check[i * prime[j]] = true;
if (i % prime[j] == 0) {
cnt[i * prime[j]] = cnt[i] + 1, val[i * prime[j]] = val[i] * prime[j];
int temp = (i * prime[j]) / val[i * prime[j]];
if (temp == 1) g[i * prime[j]] = 1;
else g[i * prime[j]] = (cnt[temp] == cnt[i * prime[j]] ? -g[temp] : 0);
break;
}
cnt[i * prime[j]] = 1, val[i * prime[j]] = prime[j];
int temp = (i * prime[j]) / val[i * prime[j]];
if (temp == 1) g[i * prime[j]] = 1;
else g[i * prime[j]] = (cnt[temp] == cnt[i * prime[j]] ? -g[temp] : 0);
}
}
for (int i = 1; i <= maxn; ++i) sum[i] = sum[i - 1] + g[i];
}
void work() {
LL a, b;
scanf("%lld%lld", &a, &b);
int le, ri, lim = min(a, b);
LL ans = 0;
for (int i = 1; i <= lim; i = ri + 1) {
le = i, ri = min(a / (a / i), b / (b / i));
ans += (a / i) * (b / i) * (sum[ri] - sum[le - 1]);
}
printf("%lld\n", ans);
}
int main() {
init();
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}