【题解】crash的数字表格

p1829 crash的数字表格

题目要我们求:

\(\displaystyle \sum_{i=1}^n\sum_{j=1}^m lcm(i,j)\) 也就是 \(\displaystyle \sum_{i=1}^n\sum_{j=1}^m \frac{ij}{gcd(i,j)}\)

然后我们熟练地接着向下化

\(\displaystyle \sum_{k=1}^{min(n,m)}\sum_{i=1}^n\sum_{j=1}^m [gcd(i,j)=k]\frac{ij}{k}\)

先去掉第一个\(sigma\),单独看后面,可以转化成

\(\displaystyle k\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor} [gcd(i,j)=1]ij\)

不看前面的k,然后莫比乌斯反演

\(\displaystyle \sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor} \sum_{d|gcd(i,j)}\mu(d) ij\)

把莫比乌斯函数提到前面

\(\displaystyle \sum_{d=1}^{min(\lfloor\frac{n}{k}\rfloor,\lfloor\frac{m}{k}\rfloor)}\mu(d) \sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor} [d|gcd(i,j)]ij\)

我们故技重施,再来一次经典转化

\(\displaystyle \sum_{d=1}^{min(\lfloor\frac{n}{k}\rfloor,\lfloor\frac{m}{k}\rfloor)}\mu(d) d^2\sum_{i=1}^{\lfloor\frac{n}{kd}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{kd}\rfloor} [1|gcd(i,j)]ij\)

也就是

\(\displaystyle \sum_{d=1}^{min(\lfloor\frac{n}{k}\rfloor,\lfloor\frac{m}{k}\rfloor)}\mu(d) d^2\sum_{i=1}^{\lfloor\frac{n}{kd}\rfloor}i\sum_{j=1}^{\lfloor\frac{m}{kd}\rfloor}j\)

然后就化完了,把之前省略掉的加上

\(\displaystyle \sum_{k=1}^{min(n,m)} k\sum_{d=1}^{min(\lfloor\frac{n}{k}\rfloor,\lfloor\frac{m}{k}\rfloor)}\mu(d) d^2\sum_{i=1}^{\lfloor\frac{n}{kd}\rfloor}i\sum_{j=1}^{\lfloor\frac{m}{kd}\rfloor}j\)

注意到后面两个\(\sum\)可以预处理,中间的莫比乌斯函数也可以预处理,然后数论分块求就好了

贴个代码吧

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define maxn 10000007
#define mod 20101009

long long n,m,sum[maxn],s[maxn];
int mu[maxn],prime[maxn],tot;
bool vis[maxn];

void getmu() {
	int k = std::max(n,m);
	mu[1] = 1;
	for (int i = 2;i <=k;i++) {
		if (!vis[i]) prime[++tot] = i,mu[i] = -1;
		for (int j = 1;j <= tot && (long long)i * prime[j] <= n;j++) {
			vis[i * prime[j]] = 1;
			if (i % prime[j] == 0) {
				mu[i * prime[j]] = 0;
				break;
			}
			mu[i * prime[j]] = -mu[i];
		}
	}
	for (int i = 1;i <= k;i++) sum[i] = (sum[i - 1] + (long long)mu[i] * (long long) i  % mod * i % mod) % mod;
	for (int i = 1;i <= k;i++) s[i] = (s[i - 1] + i) % mod;
}

int main() {
	scanf("%lld%lld",&n,&m);
	int u = std::min(n,m);
	long long ans = 0;
	getmu();
	for (int k = 1;k <= u;k++) {
		long long su = 0;
		int p = 1;
		while (p <= std::min(n / k,m / k)) {
			int r = std::min((n / k) / (n / k / p),(m / k) / (m / k / p));
			(su += (long long)(sum[r] - sum[p - 1] + mod) % mod * (long long)s[n / k / p] % mod * (long long)s[m / k / p] % mod) %= mod;
			p = r + 1;
		}
		(ans += su * k % mod) %= mod;
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2021-03-01 17:11  I11usi0ns  阅读(69)  评论(0编辑  收藏  举报