LuoguP5176 公约数 题解

题意:
\(1000\)

\[\sum_{i=1}^n\sum_{j=1}^m\sum_{k=1}^p\gcd(i\cdot j,i\cdot k,j\cdot k)\times \gcd(i,j,k)\times \left(\frac{\gcd(i,j)}{\gcd(i,k)\times \gcd(j,k)}+\frac{\gcd(i,k)}{\gcd(i,j)\times \gcd(j,k)}+\frac{\gcd(j,k)}{\gcd(i,j)\times \gcd(i,k)}\right) \]

\(n、m、p\) 规模均为 \(2e7\)


由于我蒻的一匹, 所以我看了题解。

题目的第一步是想到(或是证出来)一个结论, 如下:

\[gcd(i*j,i*k,j*k) = \frac{gcd(i,j)*gcd(i,k)*gcd(j,k)}{gcd(i,j,k)} \]

怎么证这个结论呢?

首先就是将式子里的所有项都写成质因数分解的形式。

\[gcd(i*j,i*k,j*k) = \sum_{p=1}^{\infty} p_i^{min(c_{i1}+c_{i2},c_{i1}+c_{i3},c_{i2}+c_{i3})} \]

\[gcd(i,j)*gcd(i,k)*gcd(j,k) = \sum_{p=1}^{\infty} p_i^{min(c_{i1},c_{i2})+min(c_{i1},c_{i3})+min(c_{i2},c_{i3})} \]

\[gcd(i,j,k) = \sum_{p=1}^{\infty} p_i^{min(c_{i1},c_{i2},c_{i3})} \]

于是

\[gcd(i*j,i*k,j*k) = \frac{gcd(i,j)*gcd(i,k)*gcd(j,k)}{gcd(i,j,k)} \]

\(\Leftarrow min(c_{i1}+c_{i2},c_{i1}+c_{i3},c_{i2}+c_{i3}) = min(c_{i1},c_{i2})+min(c_{i1},c_{i3})+min(c_{i2},c_{i3}) - min(c_{i1},c_{i2},c_{i3})\)

似乎还没有规定 \(c_{x1}\)\(c_{x2}\)\(c_{x3}\) 分别对应 \(i\)\(j\)\(k\) 中的哪一个, 但是无论 \(c_{x1}\)\(c_{x2}\)\(c_{x3}\) 分别对应 \(i\)\(j\)\(k\) 中的哪一个,
\(min(c_{i1}+c_{i2},c_{i1}+c_{i3},c_{i2}+c_{i3})\) 的值
\(min(c_{i1},c_{i2})+min(c_{i1},c_{i3})+min(c_{i2},c_{i3}) - min(c_{i1},c_{i2},c_{i3})\) 的值
都不会改变(因为它们都是轮换式)。

故规定 \(c_{i1} \leq c_{i2} \leq c_{i3}\), 原等式转为

\[c_{i1} + c_{i2} = c_{i1} + c_{i1} + c_{i2} - c_{i1} \]

故结论成立。


所以

\[\sum_{i=1}^n\sum_{j=1}^m\sum_{k=1}^p\gcd(i\cdot j,i\cdot k,j\cdot k)\times \gcd(i,j,k)\times \left(\frac{\gcd(i,j)}{\gcd(i,k)\times \gcd(j,k)}+\frac{\gcd(i,k)}{\gcd(i,j)\times \gcd(j,k)}+\frac{\gcd(j,k)}{\gcd(i,j)\times \gcd(i,k)}\right) \]

\[=\sum_{i=1}^n\sum_{j=1}^m\sum_{k=1}^p gcd^2(i,j) + gcd^2(i,k) + gcd^2(j,k) \]

展开

\[=\sum_{i=1}^n\sum_{j=1}^m\sum_{k=1}^p gcd^2(i,j) + \sum_{i=1}^n\sum_{j=1}^m\sum_{k=1}^p gcd^2(i,k) + \sum_{i=1}^n\sum_{j=1}^m\sum_{k=1}^p gcd^2(j,k) \]

\[= p * \sum_{i=1}^n\sum_{j=1}^m gcd^2(i,j) + m * \sum_{i=1}^n\sum_{k=1}^p gcd^2(i,k) + n * \sum_{j=1}^m\sum_{k=1}^p gcd^2(j,k) \]

把变量换得整齐点。

\[= p * \sum_{i=1}^n\sum_{j=1}^m gcd^2(i,j) + m * \sum_{i=1}^n\sum_{j=1}^p gcd^2(i,j) + n * \sum_{i=1}^m\sum_{j=1}^p gcd^2(i,j) \]

然后题目就转化为了分别求三个同样形式的式子。

那么怎么求\(\sum_{i=1}^n\sum_{j=1}^m gcd^2(i,j)\)

套路上场~~~

\(f(n) = n^2\), 则

\(\sum_{i=1}^n\sum_{j=1}^m gcd^2(i,j) = \sum_{i=1}^n\sum_{j=1}^m f(gcd(i,j))\)

要找出\(1 * g = f\), 则\(g = f * \mu\), 可以 \(O(n\log \log n)\) 卷出来, 于是

\[\sum_{i=1}^n\sum_{j=1}^m f(gcd(i,j)) \]

\[= \sum_{i=1}^n\sum_{j=1}^m \sum_{d|gcd(i,j)} g(d) \]

\[= \sum_{d=1}^{min(n,m)} g(d) \lfloor \frac{n}d \rfloor \lfloor \frac{m}d \rfloor \]

分块求即可。

Luogu数据吸氧才能AC的丑陋代码
(其实函数 \(g\) 可以线性筛出来, 但是我不想写qwq)

#include<bits/stdc++.h>
using namespace std;
const int maxn = 20000001;
const int mod = 1e9 + 7;
#define li long long

int pr_cnt, prime[maxn], v[maxn];
li g[maxn];
void euler(int n) {
	g[1] = 1ll;
	for(register int i=2; i<=n; ++i) {
		if(!v[i]) {
			v[prime[++pr_cnt] = i] = i;
			g[i] = 1ll * i * i % mod;
		}
		for(int j=1; j<=pr_cnt; ++j) {
			if(prime[j] > n/i || prime[j] > v[i]) break;
			v[prime[j] * i] = prime[j];
			g[prime[j] * i] = 1ll * g[i] * g[prime[j]] % mod;
		}
	}
	for(int i=1; i<=pr_cnt; ++i)
		for(int j=n/prime[i]; j>0; --j) {
			g[prime[i] * j] -= g[j];
			g[prime[i] * j] %= mod;
		}
	for(int i=1; i<=n; ++i) {
		g[i] += g[i-1];
		g[i] %= mod;
	}
}

li calc(li n, li m) {
	li len = min(n, m);
	li res = 0ll;
	for(register li i=1,j; i<=len; i=j+1) {
		j = min(n/(n/i), m/(m/i));
		j = min(j, len);
		res += 1ll * (g[j]-g[i-1]) * (n/i) % mod * (m/i) % mod;
		res %= mod;
	}
	return res;
}

int main()
{
	euler(20000000);
	int T; cin >> T; while(T--) {
		li n,m,p;
		scanf("%lld%lld%lld", &n,&m,&p);
		li ans = 0ll;
		ans = 1ll * p * calc(n,m) % mod;
		ans += 1ll * n * calc(m,p) % mod;
		ans %= mod;
		ans += 1ll * m * calc(n,p) % mod;
		ans = (ans%mod+mod)%mod;
		cout << ans << '\n';
	}
	return 0;
}
posted @ 2020-04-24 15:29  xwmwr  阅读(152)  评论(3编辑  收藏  举报