YY的GCD 题解

题面:
\(T = 10000\)

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

\(n\)\(m\) 规模均为 \(1e7\)


一个常见的套路是若能找到 \(g\) 使得 \(f = g*1\) \((f、g均为数论函数)\), 则

\[\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 \]


由于\(f = g * 1\) , 则 \(g = f * \mu\)

在这道题里, \(f(n) = [n为质数]\), 则
\(g(n) = \sum_{d|n} [d为质数]\mu(\frac{n}d) = \sum_{p|n} \mu(\frac{n}p)\)

所以

\[\sum_{i=1}^n \sum_{j=1}^m [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 \]

其中, \(g(n) = \sum_{p|n} \mu(\frac{n}p)\), 可以预处理。

总复杂度就是 \(O(n + T\sqrt n)\)

Luogu数据不开O2 AC代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e7 + 15;
#define li long long

int m, prime[maxn], v[maxn], f[maxn];
li g[maxn];
void euler(li n) {
	for(li i=2; i<=n; ++i) {
		if(!v[i]) {
			v[prime[++m] = i] = i;
			v[i] = i;
			f[i] = 1;
		}
		for(int j=1; j<=m; ++j) {
			if(prime[j] > n/i || prime[j] > v[i]) break;
			v[prime[j] * i] = prime[j];
		}
	}
	for(int i=1; i<=n; ++i) g[i] = f[i];
	for(int i=1; i<=m; ++i)
		for(int j=n/prime[i]; j>0; --j)
			g[prime[i] * j] -= g[j];
}
li sol(int n, int m) {
	int len = min(n,m);
	li res = 0ll;
	for(register int i=1,j; i<=len; i=j+1) {
		j = min(n/(n/i), m/(m/i));
		j = min(j, len);
		res += (g[j]-g[i-1]) * (n/i) * (m/i);
	}
	return res;
}
int main()
{
	euler(10000000);
	for(int i=2; i<=10000000; ++i) g[i] += g[i-1];
	int t; int n,m; cin >> t; while(t--) {
		scanf("%d%d", &n, &m);
		cout << sol(n, m) << '\n';
	}
	return 0;
}```
posted @ 2020-04-23 14:09  xwmwr  阅读(275)  评论(0)    收藏  举报