题解 P1447 【[NOI2010]能量采集】

题目链接

Solution [NOI2010]能量采集

题目大意:在平面直角坐标系内有(n * m)个点((x,y))(x in [1,n])(y in [1,m]),在((0,0))位置有一台机器,如果机器和点((x,y))之间的连线上有(k)个点的话那么就有(2k-1)的能量损失,给定(n,m)求能量损失之和

莫比乌斯反演


分析:

这题和[SDOI2008]仪仗队这题比较相似

假设我们可以看到一个点((x,y)),那么((lambda x,lambda y)),这个点我们是看不见的,换句话说,只有(gcd(x,y)=1)的点我们才看得见。进一步,如果(gcd(x,y)=k),那么从原点到点((x,y))的线段上有(k)个点

也就是说我们求的是这玩意儿(sum_{i=1}^nsum_{j=1}^m(2 imes gcd(i,d)-1))

莫比乌斯反演就好了qaq

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100;
int vis[maxn],n,m;
ll phi[maxn],ans;
vector<int> pri;
inline void sieve(){
	phi[1] = 1;
	for(int i = 2;i < maxn;i++){
		if(!vis[i]){
			pri.push_back(i);
			phi[i] = i - 1;
		}
		for(int x : pri){
			if(1ll * i * x >= maxn)break;
			vis[i * x] = 1;
			if(i % x)phi[i * x] = phi[i] * phi[x];
			else{
				phi[i * x] = phi[i] * x;
				break;
			}
		}
	}
	for(int i = 1;i < maxn;i++)
		phi[i] += phi[i - 1];
}
int main(){
	sieve();
	cin >> n >> m;
	for(int r,l = 1;l <= min(n,m);l = r + 1){
		r = min(min(n,m),min(n / (n / l),m / (m / l)));
		ans += 2ll * (phi[r] - phi[l - 1]) * (n / l) * (m / l);
	}
	ans -= 1ll * n * m;
	cout << ans << '
';
	return 0;
}
原文地址:https://www.cnblogs.com/colazcy/p/12350277.html