能量采集题解

( 0 , 0 ) 和 ( x , y ) 之 间 挡 了 g c d ( x , y ) − 1 个 点 (0,0)和(x,y)之间挡了gcd(x,y)-1个点 (0,0)(x,y)gcd(x,y)1

f ( x , y ) = 2 ∗ ( g c d ( x , y ) − 1 ) + 1 = 2 ∗ g c d ( x , y ) − 1 f(x,y)=2*(gcd(x,y)-1)+1=2*gcd(x,y)-1 f(x,y)=2(gcd(x,y)1)+1=2gcd(x,y)1

∑ x = 1 n ∑ y = 1 m ( 2 ∗ g c d ( x , y ) − 1 ) ∑_{x=1}^n∑_{y=1}^m(2*gcd(x,y)-1) x=1ny=1m(2gcd(x,y)1)

= 2 ∗ ∑ x = 1 n ∑ y = 1 m g c d ( x , y ) − n ∗ m =2*∑_{x=1}^n∑_{y=1}^m gcd(x,y) -n*m =2x=1ny=1mgcd(x,y)nm

目 标 ∑ x = 1 n ∑ y = 1 m g c d ( x , y ) 目标∑_{x=1}^n∑_{y=1}^m gcd(x,y) x=1ny=1mgcd(x,y)

= ∑ x = 1 n ∑ y = 1 m ∑ d ∣ g c d ( x , y ) ϕ ( d ) =∑_{x=1}^n∑_{y=1}^m∑_{d|gcd(x,y)}\phi(d) =x=1ny=1mdgcd(x,y)ϕ(d)

= ∑ ( ϕ ( d ) ∗ ⌊ n / d ⌋ ∗ ⌊ m / d ⌋ ) =∑(\phi(d)*\lfloor n/d \rfloor *\lfloor m/d \rfloor) =(ϕ(d)n/dm/d)

整 除 分 块 , 预 处 理 ϕ ( x ) 区 间 和 整除分块,预处理\phi(x)区间和 ϕ(x)

#include <cstdio>
#include <iostream>
using namespace std;
#define LL long long
#define ULL unsigned long long

template <typename T> void read (T &x) { x = 0; T f = 1;char tem = getchar ();while (tem < '0' || tem > '9') {if (tem == '-') f = -1;tem = getchar ();}while (tem >= '0' && tem <= '9') {x = (x << 1) + (x << 3) + tem - '0';tem = getchar ();}x *= f; return; }
template <typename T> void write (T x) { if (x < 0) {x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0'); }
template <typename T> void print (T x, char ch) { write (x); putchar (ch); }
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }

const int Maxn = 1e5;

int cnt, primes[Maxn + 5];
int phi[Maxn + 5]; LL pre[Maxn + 5];
bool vis[Maxn + 5];
void Euler () {
	for (int i = 2; i <= Maxn; i++) {
		if (vis[i] == 0) {
			primes[++cnt] = i;
			phi[i] = i - 1;
		}
		for (int j = 1; j <= cnt; j++) {
			if (primes[j] > Maxn / i) break;
			vis[primes[j] * i] = 1;
			if (i % primes[j] == 0) {
				phi[i * primes[j]] = phi[i] * primes[j];
				break;
			}
			phi[i * primes[j]] = phi[i] * (primes[j] - 1);
		}
	}
	phi[1] = 1;
	for (int i = 1; i <= Maxn; i++)
		pre[i] = pre[i - 1] + phi[i];
}

int main () {
	//answer = 2 * ∑∑{gcd (i, j)} - n * m
	Euler ();
	int n, m;
	read (n); read (m);
	
	int l = 1, r;
	LL res = 0;
	while (l <= Min (n, m)) {
		r = Min (n / (n / l), m / (m / l));
		res += (pre[r] - pre[l - 1]) * (n / l) * (m / l);
		l = r + 1;
	}
	write (res * 2 - (LL)n * m);
	return 0;
}
posted @ 2021-08-24 17:02  C2022lihan  阅读(14)  评论(0编辑  收藏  举报