2005: [Noi2010]能量采集

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)$

 

容斥:

 1 #include<cstdio>
 2 #include<iostream>
 3  
 4 using namespace std;
 5  
 6 typedef long long LL;
 7 const int N = 100100;
 8 LL f[N];
 9  
10 int main() {
11     LL n,m,ans = 0;
12     cin >> n >> m;
13     int mi = min(n,m);
14     for (int i=mi; i>=1; --i) {
15         f[i] = (n / i) * (m / i);
16         for (int j=i+i; j<=mi; j+=i) {
17             f[i] -= f[j];
18         }
19         ans += f[i] * i;
20     }
21     cout << 2 * ans - n * m;
22     return 0;
23 }
24 
View Code

 

莫比乌斯+欧拉函数:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 
 5 inline int read() {
 6     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
 7     for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
 8 }
 9 
10 const int N = 100010;
11 int prime[N],phi[N],tot;
12 bool noprime[N];
13 
14 void getphi(int n) {
15     phi[1] = 1;
16     for (int i=2; i<=n; ++i) {
17         if (!noprime[i]) prime[++tot] = i,phi[i] = i-1;
18         for (int j=1; j<=tot&&prime[j]*i<=n; ++j) {
19             noprime[i * prime[j]] = true;
20             if (i % prime[j] == 0) {
21                 phi[i * prime[j]] = phi[i] * prime[j];
22                 break; 
23             }
24             phi[i * prime[j]] = phi[i] * (prime[j]-1); 
25         }
26     }
27     for (int i=1; i<=n; ++i) phi[i] += phi[i-1];
28 }
29 int main() {
30     
31     LL n,m;
32     cin >> n >> m;
33     LL mi = min(n,m);
34     getphi((int)mi);
35     LL ans = 0,pos = 0;
36     for (int T=1; T<=mi; T=pos+1) {
37         pos = min(n/(n/T),m/(m/T));
38         ans += (n/T) * (m/T) * (phi[pos] - phi[T-1]);
39     }
40     cout << ans * 2 - n * m;    
41     return 0;
42 }
View Code

 

posted @ 2018-06-25 17:51  MJT12044  阅读(217)  评论(4编辑  收藏  举报