# [BZOJ2005][Noi2010]能量采集

## 2005: [Noi2010]能量采集

Time Limit: 10 Sec  Memory Limit: 552 MB Submit: 4287  Solved: 2564 [Submit][Status][Discuss]

【样例输入1】
5 4
【样例输入2】
3 4

## Sample Output

【样例输出1】
36
【样例输出2】
20

$ans=2*\sum_{i=1}^n\sum_{j=1}^m gcd\left(i,j\right)-n*m$

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 100000 + 10;
bool mark[maxn] = {false};
int pri[maxn], prn = 0;
int phi[maxn], sum[maxn];
void shai(){
phi[1] = 1;
for(int i = 2; i < maxn; i++){
if(!mark[i]){
phi[i] = i - 1;
pri[++prn] = i;
}
for(int j = 1; j <= prn && i * pri[j] < maxn; j++){
mark[i * pri[j]] = true;
if(i % pri[j] == 0){
phi[i * pri[j]] = phi[i] * pri[j];
break;
}
else phi[i * pri[j]] = phi[i] * (pri[j] - 1);
}
}
sum[0] = 0;
for(int i = 1; i < maxn; i++) sum[i] = sum[i - 1] + phi[i];
}
int main(){
shai();
int n, m;
scanf("%d %d", &n, &m);
if(n > m) swap(n, m);
ll ans = 0;
for(int p, i = 1; i <= n; i = p + 1){
p = min(n / (n / i), m / (m / i));
ans += (ll) (sum[p] - sum[i - 1]) * (n / p) * (m / p);
}
printf("%lld\n", 2LL * ans - (ll) n * m);
return 0;
}

posted @ 2017-10-16 20:19  Elder_Giang  阅读(88)  评论(0编辑  收藏  举报