[NOI2010] 能量采集

分析

等价于求 ∑ i = 1 n ∑ j = 1 m ( ( gcd ⁡ ( i , j ) − 1 ) ⋅ 2 + 1 ) \sum_{i = 1}^{n}\sum_{j = 1}^{m}((\gcd(i,j) - 1) \cdot2+1) i=1nj=1m((gcd(i,j)1)2+1)
化简 ∑ i = 1 n ∑ j = 1 m ( 2 ⋅ gcd ⁡ ( i , j ) − 1 ) = ∑ i = 1 n ∑ j = 1 m 2 ⋅ gcd ⁡ ( i , j ) − n ⋅ m = 2 ⋅ ∑ i = 1 n ∑ j = 1 m g c d ( i , j ) − n ⋅ m \sum_{i = 1}^{n}\sum_{j = 1}^{m}( 2\cdot\gcd(i,j) - 1) = \sum_{i = 1}^{n}\sum_{j = 1}^{m} 2\cdot\gcd(i,j) - n\cdot m = 2\cdot\sum_{i = 1}^{n}\sum_{j = 1}^{m} gcd(i,j) - n\cdot m i=1nj=1m(2gcd(i,j)1)=i=1nj=1m2gcd(i,j)nm=2i=1nj=1mgcd(i,j)nm
因为 i d = 1 ∗ φ id = 1 * φ id=1φ
所以原式化为 2 ⋅ ∑ i = 1 n ∑ j = 1 m ∑ k ∣ gcd ⁡ ( i , j ) φ ( k ) − n ⋅ m = 2 ⋅ ∑ k = 1 min ⁡ ( n , m ) φ ( k ) ⋅ ⌊ n k ⌋ ⋅ ⌊ m k ⌋ − n ⋅ m 2\cdot\sum_{i = 1}^{n}\sum_{j = 1}^{m} \sum_{k | \gcd(i,j)}φ(k) - n\cdot m = 2\cdot \sum_{k =1}^{\min(n,m)}φ(k)\cdot\lfloor\dfrac{n}{k}\rfloor\cdot\lfloor\dfrac{m}{k}\rfloor - n\cdot m 2i=1nj=1mkgcd(i,j)φ(k)nm=2k=1min(n,m)φ(k)knkmnm
于是可以用 O ( n ) O(n) O(n) 或者 O ( n log ⁡ n ) O(n\log{n}) O(nlogn) 的时间复杂度求 φ φ φ 的前缀和,用 O ( n ) O(\sqrt{n}) O(n ) 的时间整除分块求解。

代码

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int n, m, v[MAXN];
long long prime[MAXN], phi[MAXN], sph[MAXN], cnt = 0;

void eular (int x) {
	phi[1] = 1;
	memset (v, 0, sizeof (v));
	for (int q = 2; q <= x; ++q) {
		if (! v[q]) {
			prime[++ cnt] = q;
			phi[q] = q - 1;
		}
		for (int w = 1; w <= cnt && prime[w] * q <= x; ++w)  {
			if (prime[w] * q > x) break;
			v[prime[w] * q] = 1;
			phi[prime[w] * q] = phi[q] * phi[prime[w]];
			if ((q % prime[w]) == 0) {
				phi[prime[w] * q] = phi[q] * prime[w];
				break;
			}
		}
	}
	sph[0] = 0;
	for (int q = 1; q <= x; ++q) {
		sph[q] = sph[q - 1] + phi[q];
	}
}

long long solve (long long x, long long y) {
	long long ans = 0;
	if (x < y) swap (x, y);
	for (int l = 1, r; l <= y; l = r + 1) {
		r = min (x / (x / l), y / (y / l));
		ans += (long long) (sph[r] - sph[l - 1]) * (x / l) * (y / l);
	}
	return ans;
}

int main () {
	eular (100000);
	scanf ("%lld %lld", &n, &m);
	if (n < m) swap (n, m);
	long long sum = solve (n, m);
	sum = (long long) 2 * sum - (long long)n * m;
	printf ("%lld\n", sum);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值