DZY LOVES MATH (莫比乌斯反演)
OK!开始更新莫比乌斯反演
先看了一下数据范围,嗯,根据\(jiry\)老师的真言,我们一定是可以筛一遍然后用根号或者是\(log\)的算法。
题目思路挺简单,就是把原始的式子化成:
\(\sum_{k = 1}^{min(a,b)}(a/k)(b/k) \sum_{d | k} f(d) * \mu (k / d)\)
由于莫反的函数是建立在积性上的,但是后面那个显然不是积性。
我们考虑把后面的式子代换一下:\(g(n) = \sum_{d|n}f(n/d) * \mu(d)\)
考虑\(\mu\)这个函数,当\(x > 0\)是1,否则是0.
我们只考虑1的情况,如果是1它就只能是\(d = \prod_{p_i | d} p_i\)
\(k = (d的条件)^r\)时,\(g\)函数不为0.
此时\(g(n) = -\mu(\prod p_i)\)
然后考虑线性筛法求出\(g\)即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
inline int read () {
int q=0,f=1;char ch = getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;ch=getchar();
}
while(isdigit(ch)){
q=q*10+ch-'0';ch=getchar();
}
return q*f;
}
ll ans;
const int maxn = 10000008;
int prime[maxn];
bool is_prime[maxn];
int cnt;
int miu[maxn];
inline void init () {
cnt = 0;
memset(prime,0,sizeof(prime));
memset(is_prime,0,sizeof(is_prime));
miu[1] = 1;
for(int i = 2;i < maxn; ++i) {
if(!is_prime[i]) {
prime[++cnt] = i;
miu[i] = -1;
}
for(int j = 1;j <= cnt; ++j) {
if(i * prime[j] >= maxn) {
break;
}
else {
is_prime[i * prime[j]] = 1;
if(i % prime[j]) {
miu[i * prime[j]] = -miu[i];
}
else {
miu[i * prime[j]] = 0;
break;
}
}
}
}
// cout<<1<<endl;
}
int g[maxn];
inline void calc () {
init();
g[0] = g[1] = 0;
for(ll i = 2;i < maxn; ++i) {
if(miu[i]) {
for(ll j = i;j < maxn; j *= i) {
g[j] = -miu[i];
}
}
}
for(ll i = 2;i < maxn; ++i) {
g[i] += g[i - 1];
}
// cout<<1<<endl;
}
int T;
int main () {
calc();
T = read();
while(T--) {
int n = read(),m = read();
if(n > m) swap(n,m);
ans = 0;
for(int i = 1,j;i <= n;i = j + 1) {
j = min(n / (n / i),m / (m / i));
ans += (ll)(n / i) * (m / i) * ( g[j] - g[i - 1] );
}
printf("%lld\n",ans);
}
return 0;
}