BZOJ3529 [Sdoi2014]数表【莫比乌斯反演】

Description

有一张 n×m 的数表,其第 i 行第 j 列(1 <= i <= n, 1 <= j <= m)的数值为
能同时整除 i 和 j 的所有自然数之和。给定 a , 计算数表中不大于 a 的数之和。

Input

输入包含多组数据。
输入的第一行一个整数Q表示测试点内的数据组数
接下来Q行,每行三个整数n,m,a(|a| < =10^9)描述一组数据。
1 < =N.m < =10^5 , 1 < =Q < =2×10^4

Output

对每组数据,输出一行一个整数,表示答案模2^31的值。

Sample Input

2
4 4 3
10 10 5

Sample Output

20
148


题解%%%%贝神的blog,我就不赘述了


//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
//convenient for
#define fu(a, b, c) for (int a = b; a <= c; ++a)
#define fd(a, b, c) for (int a = b; a >= c; --a)
#define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x) {
  bool w = 1;x = 0;
  char c = getchar();
  while (!isdigit(c) && c != '-') c = getchar();
  if (c == '-') w = 0, c = getchar();
  while (isdigit(c)) {
    x = (x<<1) + (x<<3) + c -'0';
    c = getchar();
  }
  if (!w) x = -x;
}
template <typename T>
void Write(T x) {
  if (x < 0) {
    putchar('-');
    x = -x; 
  }
  if (x > 9) Write(x / 10);
  putchar(x % 10 + '0');
}
//----------------------------------------------
const int N = 1e5 + 10;
int prime[N], mu[N], tot = 0;
bool vis[N];
int sum[N], pre[N], ans[N];
struct Ques {
  int n, m, id, a;
} Q[N];
bool operator < (const Ques a, const Ques b) {
  return a.a < b.a;
}
struct Node {
  int id, vl;
} P[N];
bool operator < (const Node a, const Node b) {
  return a.vl < b.vl;
}
void init() {
  mu[1] = sum[1] = pre[1] = 1;
  P[1] = (Node){1, 1};
  fu(i, 2, N - 1) {
    if (!vis[i]) {
      prime[++tot] = i;
      mu[i] = -1;
      sum[i] = pre[i] = i + 1;
    }
    fu(j, 1, tot) {
      int nxt = i * prime[j];
      if (nxt >= N) break;
      vis[nxt] = 1;
      if (i % prime[j]) {
        pre[nxt] = prime[j] + 1;
        sum[nxt] = sum[i] * sum[prime[j]];
        mu[nxt] = -mu[i];
      } else {
        pre[nxt] = pre[i] * prime[j] + 1;
        sum[nxt] = sum[i] / pre[i] * pre[nxt];
        mu[nxt] = 0;
        break; 
      }
    }
    P[i] = (Node){i, sum[i]};
  }
}
int bit[N];
void add(int x, int vl) {
  for (; x < N; x += x & (-x)) bit[x] += vl;
}
int query(int x) {
  int res = 0;
  for (; x; x -= x & (-x)) res += bit[x];
  return res; 
} 
int main() {
  init();
  int T; Read(T);
  fu(i, 1, T) {
    Read(Q[i].n), Read(Q[i].m), Read(Q[i].a);
    Q[i].id = i; 
  }
  sort(Q + 1, Q + T + 1);
  sort(P + 1, P + N);
  int now = 1;
  fu(i, 1, T) {
    while (now < N && P[now].vl <= Q[i].a) {
      fu(j, 1, (N - 1) / P[now].id) {
        add(j * P[now].id, mu[j] * P[now].vl);
      }
      ++now;
    }
    int limit = min(Q[i].n, Q[i].m), k = 0;
    for (int j = 1; j <= limit; j = k + 1) {
      k = min(Q[i].n / (Q[i].n / j), Q[i].m / (Q[i].m / j));
      ans[Q[i].id] += (Q[i].n / j) * (Q[i].m / j) * (query(k) - query(j - 1));
    }
  }
  fu(i, 1, T) {
    Write(ans[i] & 2147483647);
    putchar('\n');
  }
  return 0;
}
posted @ 2018-10-15 20:21  Dream_maker_yk  阅读(117)  评论(0编辑  收藏  举报