[NOI2010]能量採集

提供兩種作法。ide

1.簡單容斥。spa

這題乍一看有點像[SDOI2008]儀仗隊...3d

而後咱們就想到可能跟gcd有關,而後發現點(i,j)的貢獻是gcd(i,j) * 2 - 1code

證實以下:blog

設g = gcd(i,j)get

則點(i,j)與原點連線中最靠近原點的點是it

由於此點的橫縱座標互質。io

那麼在連線上的全部點就是p, 2p, 3p...(g - 1)pevent

共有(g - 1)個點,因此是2g - 1class

稍微轉化一下,咱們枚舉g,求有多少對i,j知足gcd(i,j) = g,記爲sum[g]

咱們發現仍是不會......

咱們又發現g|gcd(i,j)的數對很好求,是

這樣咱們只要用這個值減去sum[2g],sum[3g]....便可。

倒序枚舉g便可。

long long大法好。

 1 #include <cstdio>
 2 #include <algorithm>
 3 typedef long long LL;
 4 const int N = 100010;
 5 
 6 LL sum[N];
 7 
 8 int main() {
 9     int m, n;
10     LL ans = 0;
11     scanf("%d%d", &n, &m);
12     for(int i = std::min(m, n); i >= 1; i--) {
13         sum[i] = 1ll * (m / i) * (n / i); 
14         for(int j = i << 1; j <= std::min(m, n); j += i) {
15             sum[i] -= sum[j];
16         }
17         //printf("sum[%d] = %lld \n", i, sum[i]);
18         ans += sum[i] * (i * 2 - 1);
19     }
20     printf("%lld", ans);
21     return 0;
22 }
AC代碼

 2.莫比烏斯反演。

且 ans = 2 * ∑i * f(i) - (m * n)

運用莫比烏斯反演以後的最終求和式:

 1 #include <cstdio>
 2 typedef long long LL;
 3 const int N = 100010;
 4 
 5 int n, m, c;
 6 int p[N], top, miu[N];
 7 LL f[N];
 8 bool vis[N];
 9 
10 inline void getmiu(int b) {
11     miu[1] = 1;
12     for(int i = 2; i <= b; i++) {
13         if(!vis[i]) {
14             p[++top] = i;
15             miu[i] = -1;
16         }
17         for(int j = 1; j <= top && i * p[j] <= b; j++) {
18             vis[i * p[j]] = 1;
19             if(i % p[j] == 0) {
20                 break;
21             }
22             miu[i * p[j]] = -miu[i];
23         }
24     }
25     return;
26 }
27 
28 inline LL F(int x) {
29     if(f[x]) {
30         return f[x];
31     }
32     return f[x] = 1ll * (m / x) * (n / x);
33 }
34 
35 inline LL solve(int d) {
36     LL ans = 0;
37     for(int i = 1; i * d <= c; i++) {
38         ans += F(i * d) * miu[i];
39     }
40     return ans * d;
41 }
42 
43 int main() {
44     LL ans = 0;
45     scanf("%d%d", &n, &m);
46     c = n > m ? m : n;
47     getmiu(c);
48     for(int i = 1; i <= c; i++) {
49         ans += solve(i);
50     }
51     printf("%lld", 2 * ans - 1ll * m * n);
52     return 0;
53 }
AC代碼
相關文章
相關標籤/搜索