莫比乌斯反演 bzoj 3309 DZY Loves Math

好久没有写反演了 感觉不会了
首先推一个经典的式子啊
\[ans = \sum_{D=1}^{n}\sum_{d|D}f(d)\mu(\frac{D}{d})\frac{n}{D}\frac{m}{D}\]
\(g(D) = \sum_{d|D}f(d)\mu(\frac{D}{d})\)
结论挺好找的啊
把一个数拆成\({p_k}^{a_k}\)形式
如果所有\(a_k\)相同 那么\(g(D) = (-1)^{k+1}\)
否则\(g(D) = 0\)
证明就考虑两个集合
所有次幂为最大的集合\(A\)非最大的集合\(B\)
\(f\)其实取决于\(A\)
\(\mu\)取决于选取的总个数

如果所有\(a_k\)相同 都可以使得\(\mu\)奇偶相同从而是0
但是如果选了A整个集合 要多减一个1
那么答案是\((-1)^{k+1}\)

否则都可以使得\(\mu\)奇偶相同从而是0

复杂度\(\mathcal O(T \sqrt n + n)\)

#include <bits/stdc++.h>
#define int long long
#define fo(i, n) for(int i = 1; i <= (n); i ++)
#define out(x) cerr << #x << " = " << x << "\n"
#define type(x) __typeof((x).begin())
#define foreach(it, x) for(type(x) it = (x).begin(); it != (x).end(); ++ it)
using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
  x = 0;char c = getchar(); bool f = 0;
  for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
  for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
  if(f) x = -x;
}
template<typename tp> inline void arr(tp *a, int n) {
  for(int i = 1; i <= n; i ++)
    cout << a[i] << " ";
  puts("");
}
const int N = 1e7 + 233;
#define P pair<int, int>
int np[N], g[N], p[N], p_cnt = 0;
P f[N];
inline void seive(int n) {
  np[1] = 1; f[1] = P(0, 1); g[1] = 0;
  for(int i = 2; i <= n; i ++) {
    if(!np[i]) p[++ p_cnt] = i, f[i] = P(1, 1), g[i] = 1;
    for(int j = 1; j <= p_cnt && p[j] * i <= n; j ++) {
      int k = i * p[j];
      np[k] = 1;
      if(i % p[j] == 0) {
        int del = f[i].first;
        f[k] = P(del, f[i].second + 1);
        if(del == 1) g[k] = 1;
        else g[k] = f[k].second == f[del].second ? -g[del] : 0;
        break;
      }
      else {
        int del = i;
        f[k] = P(i, 1);
        if(del == 1) g[k] = 1;
        else g[k] = f[k].second == f[del].second ? -g[del] : 0;
      }
    }
  }
  fo(i, n) g[i] += g[i - 1];
}

inline int F(int n, int m) {
  return n * m;
}

inline int doit(int n, int m) {
  if(n > m) swap(n, m);
  int ans = 0;
  for(int i = 1, last = 0; i <= n; i = last + 1) {
    last = min(n / (n / i), m / (m / i));
    ans += F(n / i, m / i) * (g[last] - g[i - 1]);
  }
  return ans;
}

main(void) {
  seive(N);
  int T;
  for(read(T); T --;) {
    int a, b;
    cin >> a >> b;
    cout << doit(a, b) << "\n";
  }
}

猜你喜欢

转载自www.cnblogs.com/foreverpiano/p/9032855.html