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;
}