莫比乌斯反演题目结(下)

莫比乌斯题目结(上)

BZOJ3994

大佬们推公式的手段是怎么学到的……qwq完全想不到啊qwq

学习的是这篇博客的推公式。

要点节选:

1.结论:d(i*j)是i*j的约数个数,则

2.又用到莫比乌斯函数的性质

3.枚举项的更换。约数整除枚举的和搭配真值式往往可以替代为常数块,而直接枚举符合真值的数可以省去真值。

数学推导出来以后,代码就不复杂了。

 1 #pragma comment(linker, "/STACK:1024000000,1024000000")
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 #include <ctime>
 7 #include <cctype>
 8 #include <climits>
 9 #include <iostream>
10 #include <iomanip>
11 #include <algorithm>
12 #include <string>
13 #include <sstream>
14 #include <stack>
15 #include <queue>
16 #include <set>
17 #include <map>
18 #include <vector>
19 #include <list>
20 #include <fstream>
21 #include <bitset>
22 #define init(a, b) memset(a, b, sizeof(a))
23 #define rep(i, a, b) for (int i = a; i <= b; i++)
24 #define irep(i, a, b) for (int i = a; i >= b; i--)
25 using namespace std;
26 
27 typedef double db;
28 typedef long long ll;
29 typedef unsigned long long ull;
30 typedef pair<int, int> P;
31 const int inf = 0x3f3f3f3f;
32 const ll INF = 1e18;
33 
34 template <typename T> void read(T &x) {
35     x = 0;
36     int s = 1, c = getchar();
37     for (; !isdigit(c); c = getchar())
38         if (c == '-')    s = -1;
39     for (; isdigit(c); c = getchar())
40         x = x * 10 + c - 48;
41     x *= s;
42 }
43 
44 template <typename T> void write(T x) {
45     if (x < 0)    x = -x, putchar('-');
46     if (x > 9)    write(x / 10);
47     putchar(x % 10 + '0');
48 }
49 
50 template <typename T> void writeln(T x) {
51     write(x);
52     puts("");
53 }
54 
55 const int maxn = 5e4 + 5;
56 int T, n, m;
57 int mu[maxn], primes[maxn], tot;
58 ll sum[maxn], g[maxn];
59 bool vis[maxn];
60 
61 void pre(int n) {
62     mu[1] = 1;
63     rep(i, 2, n) {
64         if (!vis[i]) {
65             mu[i] = -1;
66             primes[++tot] = i;
67         }
68         for (int j = 1; j <= tot && primes[j] * i <= n; j++) {
69             vis[primes[j] * i] = true;
70             if (i % primes[j] == 0)    break;
71             mu[primes[j] * i] = -mu[i];
72         }
73     }
74     rep(i, 1, n)    sum[i] = sum[i - 1] + mu[i];
75     rep(t, 1, n) {
76         ll tmp = 0ll;
77         for (int l = 1, r; l <= t; l = r + 1) {
78             r = t / (t / l);
79             tmp += (ll)(r - l + 1) * (t / l);
80         }
81         g[t] = tmp;
82     }
83 }
84 
85 int main() {
86     pre(maxn - 5);
87     for (read(T); T; T--) {
88         read(n), read(m);
89         if (n > m)    swap(n, m);
90         ll ans = 0ll;
91         for (int l = 1, r; l <= n; l = r + 1) {
92             r = min(n / (n / l), m / (m / l));
93             ans += (sum[r] - sum[l - 1]) * g[n / l] * g[m / l];
94         }
95         writeln(ans);
96     }
97     return 0;
98 }
bzoj3994

BZOJ3529

首先是得推公式, 学习的这个PPT,核心:

这公式根本想不到啊嘤~

那么这样子以后就是操作问题了:1.离线,按a的大小把询问排序;2.不断往树状数组里插入符合当前a值的F*mu;3.对于每个询问a,分块得到ans,这时往常的sum[r]-sum[l-1]就用BIT的query(r) - query(l-1)来得到了,特殊的前缀和。3.取模的方法也很有趣,自由爆int……

  1 #pragma comment(linker, "/STACK:1024000000,1024000000")
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <cmath>
  6 #include <ctime>
  7 #include <cctype>
  8 #include <climits>
  9 #include <iostream>
 10 #include <iomanip>
 11 #include <algorithm>
 12 #include <string>
 13 #include <sstream>
 14 #include <stack>
 15 #include <queue>
 16 #include <set>
 17 #include <map>
 18 #include <vector>
 19 #include <list>
 20 #include <fstream>
 21 #include <bitset>
 22 #define init(a, b) memset(a, b, sizeof(a))
 23 #define rep(i, a, b) for (int i = a; i <= b; i++)
 24 #define irep(i, a, b) for (int i = a; i >= b; i--)
 25 using namespace std;
 26 
 27 typedef double db;
 28 typedef long long ll;
 29 typedef unsigned long long ull;
 30 typedef pair<int, int> P;
 31 const int inf = 0x3f3f3f3f;
 32 const ll INF = 1e18;
 33 
 34 template <typename T> void read(T &x) {
 35     x = 0;
 36     int s = 1, c = getchar();
 37     for (; !isdigit(c); c = getchar())
 38         if (c == '-')    s = -1;
 39     for (; isdigit(c); c = getchar())
 40         x = x * 10 + c - 48;
 41     x *= s;
 42 }
 43 
 44 template <typename T> void write(T x) {
 45     if (x < 0)    x = -x, putchar('-');
 46     if (x > 9)    write(x / 10);
 47     putchar(x % 10 + '0');
 48 }
 49 
 50 template <typename T> void writeln(T x) {
 51     write(x);
 52     puts("");
 53 }
 54 
 55 const int maxn = 1e5 + 5, maxq = 2e4 + 5;
 56 int n, m, a, Q, mx;
 57 int mu[maxn], primes[maxn], tot, ans[maxq];
 58 bool vis[maxn];
 59 P F[maxn];
 60 
 61 struct node {
 62     int n, m, a, id;
 63 
 64     bool operator < (const node &b) const {
 65         return a < b.a;
 66     }
 67 }T[maxq];
 68 
 69 struct BIT {
 70     int t[maxn];
 71 
 72     void add(int x, int val) {
 73         for (int i = x; i <= mx; i += i&-i)
 74             t[i] += val;
 75     }
 76 
 77     int query(int x) {
 78         int ret = 0;
 79         for (int i = x; i; i -= i&-i)
 80             ret += t[i];
 81         return ret;
 82     }
 83 }bit;
 84 
 85 void pre(int n) {
 86     mu[1] = 1;
 87     rep(i, 2, n) {
 88         if (!vis[i]) {
 89             mu[i] = -1;
 90             primes[++tot] = i;
 91         }
 92         for (int j = 1; j <= tot && primes[j] * i <= n; j++) {
 93             vis[primes[j] * i] = true;
 94             if (i % primes[j] == 0)    break;
 95             mu[primes[j] * i] = -mu[i];
 96         }
 97     }
 98     rep(i, 1, n) {
 99         for (int j = i; j <= n; j += i) {
100             F[j].first += i;
101         }
102     }
103     rep(i, 1, n)    F[i].second = i;
104 }
105 
106 void solve(int i) {
107     int id = T[i].id, n = T[i].n, m = T[i].m;
108     for (int l = 1, r; l <= n; l = r + 1) {
109         r = min(n / (n / l), m / (m / l));
110         ans[id] += (n / l) * (m / l) * (bit.query(r) - bit.query(l - 1));
111     }
112 }
113 
114 int main() {
115     read(Q);
116     rep(i, 1, Q) {
117         read(n), read(m), read(a);
118         if (n > m)    swap(n, m);
119         T[i] = {n, m, a, i};
120         mx = max(mx, n);
121     }
122     pre(mx);
123     sort(F + 1, F + 1 + mx);
124     sort(T + 1, T + 1 + Q);
125     int now = 0;
126     rep(i, 1, Q) {
127         while(now + 1 <= mx && F[now + 1].first <= T[i].a) {
128             now++;
129             for (int j = F[now].second; j <= mx; j += F[now].second)
130                 bit.add(j, F[now].first * mu[j / F[now].second]);
131         }
132         solve(i);
133     }
134     rep(i, 1, Q)    writeln(ans[i]&0x7fffffff);
135     return 0;
136 }
bzoj3529

bzoj:4816、题单题单题单、洛谷试炼场专题

-----未完待续-----

原文地址:https://www.cnblogs.com/AlphaWA/p/10492681.html