您的位置:首页 > 其它

2005: [Noi2010]能量采集

2018-06-25 17:51 239 查看

2005: [Noi2010]能量采集

链接

 

分析

答案要求 $ans=2\sum\limits_{x=1}^n \sum\limits_{y=1}^mgcd(x,y)-n \times m$

主要求出中间的那一块就好了。

思路一:

  容斥:f[i]表示gcd(x,y)=i的对数。(n/i)*(m/i)是gcd(x,y)=i的倍数 的对数。那么f[i] -= f[2*i] - f[3*i] ...就好了。

思路二:

  莫比乌斯反演

$\ \ \ \ \sum\limits_{x=1}^n \sum\limits_{y=1}^mgcd(x,y)$
$=\sum\limits_p^{min(n,m)} p \sum\limits_{x=1}^n \sum\limits_{y=1}^m[gcd(x,y)=p]$
$=\sum\limits_p^{min(n,m)} p \sum\limits_d^{min(\frac{n}{p},\frac{m}{p})}μ(d)\frac{n}{pd}\times \frac{m}{pd}$
$\ \ \ \ \sum\limits_T^{min(n,m)} \frac{n}{T}\times \frac{m}{T} \sum\limits_{p|T}p \times μ(\frac{T}{p})$
$=\sum\limits_T^{min(n,m)} \frac{n}{T}\times \frac{m}{T} \ φ(T)$

 

容斥:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

inline int read() {
int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 100010;
int prime
,phi
,tot;
bool noprime
;

void getphi(int n) {
phi[1] = 1;
for (int i=2; i<=n; ++i) {
if (!noprime[i]) prime[++tot] = i,phi[i] = i-1;
for (int j=1; j<=tot&&prime[j]*i<=n; ++j) {
noprime[i * prime[j]] = true;
if (i % prime[j] == 0) {
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
phi[i * prime[j]] = phi[i] * (prime[j]-1);
}
}
for (int i=1; i<=n; ++i) phi[i] += phi[i-1];
}
int main() {

LL n,m;
cin >> n >> m;
LL mi = min(n,m);
getphi((int)mi);
LL ans = 0,pos = 0;
for (int T=1; T<=mi; T=pos+1) {
pos = min(n/(n/T),m/(m/T));
ans += (n/T) * (m/T) * (phi[pos] - phi[T-1]);
}
cout << ans * 2 - n * m;
return 0;
}
View Code

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: