【洛谷P3455】ZAP-Queries

题目大意:求 $$\sum\limits_{i=1}a\sum\limits_{j=1}b[gcd(i,j)=c]$$

题解:学会了狄利克雷卷积。

\[\epsilon=\mu \ast 1 \]

将艾弗森表达式转化成卷积的形式,在调换求和顺序,消去不必要的和式。最后利用除法分块+预处理的莫比乌斯函数前缀和在 \(O(\sqrt n)\) 时间内单次回答询问。

代码如下

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int maxn = 5e4 + 10;

int mu[maxn], sum[maxn];
vector<int> primes;
bool vis[maxn];

void RunLinearSieve() {
  mu[1] = 1, vis[1] = 1;
  int n = 5e4;
  for (int i = 2; i <= n; i++) {
    if (!vis[i]) {
      primes.push_back(i);
      mu[i] = -1;
    }
    for (int j = 0; i * primes[j] <= n; j++) {
      vis[i * primes[j]] = 1;
      if (i % primes[j] == 0) {
        mu[i * primes[j]] = 0;
        break;
      } else {
        mu[i * primes[j]] = -mu[i];
      }
    }
  }
  for (int i = 1; i <= n; i++) {
    sum[i] = sum[i - 1] + mu[i];
  }
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0), cout.tie(0);
  int T;
  cin >> T;
  RunLinearSieve();
  while (T--) {
    LL a, b, c;
    cin >> a >> b >> c;
    a /= c, b /= c;
    LL range = min(a, b);
    LL ans = 0;
    for (int i = 1; i <= range; i++) {
      int j = min(a / (a / i), b / (b / i));
      ans += (LL)(sum[j] - sum[i - 1]) * (a / i) * (b / i);
      i = j;
    }
    cout << ans << endl;
  }
  return 0;
}
posted @ 2019-04-15 21:20  shellpicker  阅读(112)  评论(0编辑  收藏  举报