题目链接

solution

\(orz\)一波大佬,然后扔上一个公式\(233\)

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

\[d(ij)\sum\limits_{x | i}\sum\limits_{y|j}[gcd(x,y)==1] \]

是不是看到这个公式瞬间就有思路了。

我们开始推柿子。

\[\sum\limits_{i=1}^n\sum\limits_{j=1}^m d(ij)\\ =\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{x|i}\sum\limits_{y|j}[gcd(x,y)==1]\\ =\sum\limits_{x=1}^n\sum\limits_{y=1}^m\lfloor\frac{n}{x}\rfloor\lfloor\frac{m}{y}\rfloor\sum\limits_{d|gcd(x,y)}\mu(d)\\ =\sum\limits_{d=1}^n\mu(d)\sum\limits_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{y=1}^{\lfloor\frac{m}{d}\rfloor}\lfloor\frac{n}{dx}\rfloor\lfloor\frac{m}{dy}\rfloor\\=\sum\limits_{d=1}^n\mu(d)\sum\limits_{x=1}^{\lfloor\frac{n}{d}\rfloor}\lfloor\frac{n}{dx}\rfloor\sum\limits_{y=1}^{\lfloor\frac{m}{d}\rfloor}\lfloor\frac{m}{dy}\rfloor \]

\(f(n)=\sum\limits_{i=1}^n\lfloor\frac{n}{i}\rfloor\)

我们可以利用整除分块在\(O(n\sqrt{n})\)的复杂度内预处理所有的\(f\)

所以原式=

\[\sum\limits_{d=1}^n\mu(d)f(\lfloor\frac{n}{d}\rfloor)f(\lfloor\frac{m}{d}\rfloor) \]

因为\(f\)都已经预处理出来,所以只要整除分块,就可以在\(O(\sqrt{n})\)的复杂度内计算每次询问了。

code

/*
* @Author: wxyww
* @Date:   2020-04-23 19:36:37
* @Last Modified time: 2020-04-23 20:04:55
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 50010;
ll read() {
	ll x = 0,f = 1;char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1; c = getchar();
	}
	while(c >= '0' && c <= '9') {
		x = x * 10 + c - '0'; c = getchar();
	}
	return x * f;
}
int prime[N],tot,mu[N],vis[N];
void pre() {
	mu[1] = 1;
	for(int i = 2;i <= 50000;++i) {
		if(!vis[i]) {
			prime[++tot] = i;
			mu[i] = -1;
		}
		for(int j = 1;j <= tot && prime[j] * i <= 50000;++j) {
			vis[prime[j] * i] = 1;
			if(i % prime[j])
				mu[i * prime[j]] = -mu[i];
			else break;
		}
	}
	for(int i = 1;i <= 50000;++i) mu[i] += mu[i - 1];
}
ll f[N];
int main() {
	pre();
	
	for(int i = 1;i <= 50000;++i) {
		for(int l = 1,r;l <= i;l = r + 1) {
			r = i / (i / l);
			f[i] += (r - l + 1) * (i / l);
		}
	}


	int T = read();
	while(T--) {
		int n = read(),m = read();
		if(n > m) swap(n,m);
		ll ans = 0;
		for(int l = 1,r;l <= n;l = r + 1) {
			r = min(n / (n / l),m / (m / l));
			ans += 1ll * (mu[r] - mu[l - 1]) * f[n / l] * f[m / l];
		}
		printf("%lld\n",ans);
	}
	return 0;
}
扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄