浏览器标题切换
浏览器标题切换end
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

LuoguP2398 GCD SUM

题目地址

题目链接

题目描述

for i=1 to n

for j=1 to n

 sum+=gcd(i,j)

给出n求sum. gcd(x,y)表示x,y的最大公约数.

输入输出格式

输入格式:

n

输出格式:

sum

输入输出样例

输入样例#1:

复制

2

输出样例#1:

复制

5

说明

数据范围 30% n<=3000 60% 7000<=n<=7100 100% n<=100000

题解

这东西其实就是\(\large\sum_{i=1}^n\sum_{j=1}^ngcd(i,j)\)
但是这个求和并不好搞,我们可以转化一下变成\(\large[gcd(i,j)=k]\)的类似形式
然后可以用莫比乌斯函数的性质来搞,也可以反演
因为不会反演,所以就放一个用性质的推导(这里的除法都是整除)

\[\large{ \begin{align*} &\sum_{i=1}^n\sum_{j=1}^ngcd(i,j)\\ &=\sum_{d=1}^nd\sum_{i=1}^n\sum_{j=1}^n{[gcd(i,j)=d]}\\ &=\sum_{d=1}^nd\sum_{i=1}^{n/d}\sum_{j=1}^{n/d}{[gcd(i,j)=1]}\\ &=\sum_{d=1}^nd\sum_{i=1}^{n/d}\sum_{j=1}^{n/d}\sum_{k|gcd(i,j)}\mu(k)\\ &=\sum_{d=1}^nd\sum_{k=1}^{n/d}\sum_{i=1}^{n/d/k}\sum_{j=1}^{n/d/k}\mu(k)*(n/d/k)^2\\ \end{align*} } \]

#include <bits/stdc++.h>
using namespace std;

#define ll long long
const int N = 1e5 + 10;

int p[N], mu[N], vis[N], sum[N];
int n, cnt = 0;
ll ans = 0;

void init() {
	mu[1] = 1;
	for(int i = 2; i < N; ++i) {
		if(!vis[i]) {p[++cnt] = i; mu[i] = -1;}
		for(int j = 1; j <= cnt && p[j] * i < N; ++j) {
			vis[p[j] * i] = 1;
			if(i % p[j] == 0) break;
			mu[i * p[j]] -= mu[i];
		}
	}
	for(int i = 1; i < N; ++i) sum[i] = sum[i - 1] + mu[i];
}

ll calc(int n) {
	ll s = 0;
	for(int l = 1, r; l <= n; l = r + 1) {
		r = n / (n / l);
		s += (ll)((ll)(n/l) * (ll)(n/l) * (ll)(sum[r] - sum[l - 1]));
	}
	return s;
}

int main() {
	init();
	scanf("%d", &n);
	for(int d = 1; d <= n; ++d) {
		ans += 1ll * d * calc(n / d);
	}
	printf("%lld\n", ans);
}
posted @ 2019-01-04 22:12  henry_y  阅读(129)  评论(0编辑  收藏  举报