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;
}
posted @ 2026-03-14 10:55  constexpr_ll  阅读(3)  评论(0)    收藏  举报