luogu P3327 [SDOI2015]约数个数和

题目链接

\[\begin{aligned} \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} [(x,y)=1]\\ &=\sum\limits_{x=1}^n\sum\limits_{y=1}^m[(x,y)=1]\lfloor \frac{n}{x}\rfloor \lfloor\frac{m}{y}\rfloor\\ &=\sum\limits_{x=1}^n\sum\limits_{y=1}^m\sum\limits_{d|x,y}\mu(d)\lfloor \frac{n}{x}\rfloor \lfloor\frac{m}{y}\rfloor\\ &=\sum\limits_{d=1}^n\mu(d)\sum\limits_{x=1}^{n/d}\sum\limits_{y=1}^{m/d}\lfloor \frac{n}{xd}\rfloor \lfloor\frac{m}{yd}\rfloor\\ &=\sum\limits_{d=1}^n\mu(d)\sum\limits_{x=1}^{n/d}d(x)\sum\limits_{y=1}^{m/d}d(y) \end{aligned} \]

预处理函数 \(d(x),\mu(x)\) 的前缀和然后整除分块即可。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define int long long

using namespace std;

const int N = 50000;
int n, m, u[N + 9], a[N + 9], p[N], cnt, d[N + 9];

void prework()
{
	u[1] = d[1] = 1;
	for (int i = 2; i <= N; i++)
	{
		if (!a[i])
			a[i] = i, p[++cnt] = i, u[i] = -1, d[i] = 2;
		for (int j = 1; j <= cnt; j++)
		{
			if (p[j] > a[i] || p[j] > N / i)
				break;
			a[p[j] * i] = p[j];
			if (i % p[j] != 0)
				u[p[j] * i] = u[p[j]] * u[i],
				d[p[j] * i] = d[p[j]] * d[i];
			else
				d[p[j] * i] = 2 * d[i] - d[i / p[j]];
		}
	}
	for (int i = 1; i <= N; i++)
		d[i] += d[i - 1], u[i] += u[i - 1];
}

signed main()
{
	prework();
	int T;
	scanf("%lld", &T);
	while (T--)
	{
		scanf("%lld %lld", &n, &m);
		if (n > m) swap(n, m);
		int ans = 0;
		for (int i = 1; i <= n; i++)
		{
			int k = min(n / (n / i), m / (m / i));
			ans += d[n / i] * d[m / i] * (u[k] - u[i - 1]);
			i = k;
		}
		printf("%lld\n", ans);
	}
}
posted @ 2020-09-22 21:27  With_penguin  阅读(90)  评论(0编辑  收藏  举报