首页 > 技术文章 > [国家集训队]Crash的数字表格 / JZPTAB 莫比乌斯反演

ww3113306 2018-09-30 19:37 原文

~~~题面~~~

题解:
  $$ans = \sum_{i = 1}^{n}\sum_{j = 1}^{m}{\frac{ij}{gcd(i, j)}}$$
  改成枚举d(设n < m)
  $$ans = \sum_{d = 1}^{n}\sum_{i = 1}^{n}\sum_{j = 1}^{m}[gcd(i, j) == d]\frac{ij}{d}$$
  考虑枚举$id$
  设$N = \lfloor{\frac{n}{d}}\rfloor$,$M = \lfloor{\frac{m}{d}}\rfloor$
  $$ans = \sum_{d = 1}^{n}{d}\sum_{i = 1}^{N}\sum_{j = 1}^{M}\sum_{t | gcd(i, j)}{\mu(t)ij}$$
  把后面改成枚举$\mu(t)$
  $$ans = \sum_{d = 1}^{n}d\sum_{t = 1}^{N}{\mu(t)} \sum_{i = 1}^{\lfloor{\frac{N}{t}}\rfloor}\sum_{j = 1}^{\lfloor{\frac{M}{t}}\rfloor}ijt^2$$
  $$ans = \sum_{d = 1}^{n}d\sum_{t = 1}^{N}{\mu(t)} t^2 \sum_{i = 1}^{\lfloor{\frac{N}{t}}\rfloor}\sum_{j = 1}^{\lfloor{\frac{M}{t}}\rfloor}ij$$
  $$ans = \sum_{d = 1}^{n}d\sum_{t = 1}^{N}{\mu(t)} t^2 \sum_{i = 1}^{\lfloor{\frac{N}{t}}\rfloor}i\sum_{j = 1}^{\lfloor{\frac{M}{t}}\rfloor}j$$
  因为$\sum_{i = 1}^{\lfloor{\frac{N}{t}}\rfloor}i$显然是可以$O(n)$预处理的,而$\lfloor{\frac{N}{t}}\rfloor \lfloor{\frac{M}{t}}\rfloor$可以整数分块,$t^2\mu(t)$可以线性筛$O(n)$预处理,总复杂度$O(n + n\sqrt{n})$

  不过其实还有更优的方法,以后再说吧。。。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define R register int
 4 #define AC 10000010
 5 #define p 20101009
 6 #define LL long long
 7 
 8 int n, m, N, M, tot;
 9 LL ans;
10 int prime[AC], mu[AC];
11 LL sum[AC], s[AC];//质数,mu函数,1~n求和,mu(t)*t^2求和
12 bool z[AC];
13 
14 void pre()
15 {
16     scanf("%d%d", &n, &m);
17     mu[1] = 1;
18     int b = max(n, m), x;
19     s[1] = sum[1] = 1;//初始化1,,,,因为下面的i是从2开始的
20     for(R i = 2; i <= b; i++)
21     {
22         if(!z[i]) prime[++tot] = i, mu[i] = -1;
23         s[i] = (s[i - 1] + (LL)mu[i] * ((LL)i * (LL)i)%p) % p;//error !!, mu要LL
24         sum[i] = (sum[i - 1] + i) % p;
25         for(R j = 1; j <= tot; j ++)
26         {
27             x = prime[j];
28             if(i * x > b) break;
29             z[i * x] = true;
30             if(!(i % x)) break;
31             mu[i * x] = -mu[i];
32         }
33     }
34 }
35 
36 void work()
37 {
38     if(m < n) swap(n, m);
39     //for(R i = 1; i <= m; i ++) printf("%lld ", sum[i]);
40     //printf("\n");
41     LL summ;
42     for(R i = 1; i <= n; i++)//枚举d
43     {
44         int pos;
45         N = n / i, M = m / i;
46         summ = 0;
47         for(R j = 1; j <= N; j = pos + 1)//枚举t
48         {
49             pos = min(N / (N / j), M / (M / j));
50             summ += (((s[pos] - s[j - 1]) % p * sum[N / j]) % p * sum[M / j]) % p;
51             summ %= p;
52         }
53         summ = (summ * i + p) % p;//error!!!别把d给忘了!
54         ans = (ans + summ + p) % p;
55         //printf("%lld\n", ans);
56     }
57     printf("%lld\n", ans);
58 }
59 
60 int main()
61 {
62 //    freopen("in.in", "r", stdin);
63     pre();
64     work();
65 //    fclose(stdin);
66     return 0;
67 }
View Code

 

推荐阅读