P3327 学习笔记
给定 \(n,m\),求
\[\sum_{i=1}^n \sum_{j=1}^m d(ij)
\]
的值。
而
\[d(ij)=\sum_{s \mid i} \sum_{t \mid j} [\gcd(s,t)=1]
\]
则
\[\begin{align*}
\sum_{i=1}^n \sum_{j=1}^m d(ij)&=\sum_{i=1}^n \sum_{j=1}^m \sum_{s \mid i} \sum_{t \mid j} [\gcd(s,t)=1]\\
&=\sum_{s=1}^n \sum_{t=1}^m [\gcd(s,t)=1] \cdot \lfloor \frac ns \rfloor \cdot \lfloor \frac mt \rfloor\\
&=\sum_{s=1}^n \sum_{t=1}^m \lfloor \frac ns \rfloor \lfloor \frac mt \rfloor\sum_{k \mid \gcd(s,t)} \mu(k)\\
&=\sum_{k=1}^{\min(n,m)} \mu(k) \sum_{s=1}^{\lfloor n/k \rfloor} \sum_{t=1}^{\lfloor m/k \rfloor} \lfloor \frac n{sk} \rfloor \lfloor \frac m{tk} \rfloor\\
\end{align*}
\]
记
\[f(k)=\sum_{i=1}^k \lfloor \frac ki \rfloor
\]
则
\[\sum_{i=1}^n \sum_{j=1}^m d(ij)=\sum_{k=1}^{\min(n,m)} \mu(k) \cdot f(\lfloor \frac nk \rfloor) \cdot f(\lfloor \frac mk \rfloor)
\]
线性筛预处理 \(\mu(k)\) 的前缀和然后整除分块即可。
code
#include <bits/stdc++.h>
#define pub public:
#define pri private:
#define fri friend:
#define Ofile(s) freopen(s".in", "r", stdin), freopen (s".out", "w", stdout)
#define Cfile(s) fclose(stdin), fclose(stdout)
#define fast ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
using namespace std;
using ll = long long;
using ull = unsigned long long;
using lb = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pil = pair<int, ll>;
using pli = pair<ll, int>;
constexpr int mod = 998244353;
constexpr int maxn = 5e4 + 5;
ll t;
ll n, m, tot;
ll mubius[maxn];
ll prime[maxn];
ll mubius_pre[maxn];
ll f[maxn];//这个题卡常,要记忆化一下
bool vis[maxn];
void init();
ll calc(ll x);
ll solve(ll x, ll y);
int main() {
freopen("std.in", "r", stdin);
freopen("std.out", "w", stdout);
fast;
init();
cin >> t;
while (t--){
cin >> n >> m;
cout << solve(n, m) << '\n';//这个题卡常,endl会T飞
}
return 0;
}
void init(){
mubius[1] = 1;
for (ll i = 2; i <= maxn - 5; i++){
if (!vis[i])
prime[++tot] = i, mubius[i] = -1;
for (ll j = 1; j <= tot && i * prime[j] <= maxn - 5; j++){
vis[i * prime[j]] = true;
if (!(i % prime[j]))
break;
else
mubius[i * prime[j]] = -mubius[i];
}
}
for (ll i = 1; i <= maxn - 5; i++)
mubius_pre[i] = mubius_pre[i - 1] + mubius[i];
for (ll i = 1; i <= maxn - 5; i++)
f[i] = calc(i);
}
ll calc(ll x){
ll res = 0;
for (ll pl = 1, pr; pl <= x; pl = pr + 1){
pr = x / (x / pl);
res += (x / pl) * (pr - pl + 1);
}
return res;
} // 常规整除分块
ll solve(ll x, ll y){
ll res = 0;
for (ll pl = 1, pr; pl <= min(x, y); pl = pr + 1){
pr = min(x / (x / pl), y / (y / pl));
res += (mubius_pre[pr] - mubius_pre[pl - 1]) * f[x / pl] * f[y / pl];
}
return res;
}

浙公网安备 33010602011771号