Skip to content

subarray_gcd.hpp

SECTIONMath INCLUDEnoya/subarray_gcd.hpp

按每个右端点压缩所有子数组 gcd;用于统计 gcd 等于某值的子数组数量或贡献。

\[ \displaystyle \gcd(a_l,\dots,a_r) \]

Complexity: Time: O(n log A). Space: O(log A) frontier per endpoint, excluding aggregate output.

跳到代码 · GitHub ↗

Implementation

当前头文件,省略 include guard;依赖见 #include

/// @complexity Time: O(n log A).
/// Space: O(log A) frontier per endpoint, excluding aggregate output.

#include <algorithm>
#include <cstdlib>
#include <cstdint>
#include <map>
#include <numeric>
#include <type_traits>
#include <utility>
#include <vector>

namespace noya {

/// @brief For every right endpoint, group all nonempty suffixes by gcd in
/// O(n log V) total groups.
template <class Int>
std::vector<std::vector<std::pair<Int, std::uint64_t>>>
subarray_gcd_suffix_groups(const std::vector<Int> &vs) {
  static_assert(std::is_integral_v<Int>);
  std::vector<std::vector<std::pair<Int, std::uint64_t>>> res;
  res.reserve(vs.size());
  std::vector<std::pair<Int, std::uint64_t>> pre;
  for (Int val : vs) {
    std::vector<std::pair<Int, std::uint64_t>> cur;
    auto app = [&](Int div, std::uint64_t cnt) {
      if (!cur.empty() && cur.back().first == div) {
        cur.back().second += cnt;
      } else {
        cur.emplace_back(div, cnt);
      }
    };
    app(std::abs(val), 1);
    for (auto [div, cnt] : pre) {
      app(std::gcd(div, val), cnt);
    }
    res.push_back(cur);
    pre = std::move(cur);
  }
  return res;
}

/// @brief Count subarrays by their gcd; returned pairs are sorted by gcd.
template <class Int>
std::vector<std::pair<Int, std::uint64_t>>
subarray_gcd_counts(const std::vector<Int> &vs) {
  std::map<Int, std::uint64_t> cou;
  for (const auto &gro : subarray_gcd_suffix_groups(vs)) {
    for (auto [div, cnt] : gro) {
      cou[div] += cnt;
    }
  }
  return {cou.begin(), cou.end()};
}

} // namespace noya
#ifndef NOYA_SUBARRAY_GCD_HPP
#define NOYA_SUBARRAY_GCD_HPP 1

/// @complexity Time: O(n log A).
/// Space: O(log A) frontier per endpoint, excluding aggregate output.

#include <algorithm>
#include <cstdlib>
#include <cstdint>
#include <map>
#include <numeric>
#include <type_traits>
#include <utility>
#include <vector>

namespace noya {

/// @brief For every right endpoint, group all nonempty suffixes by gcd in
/// O(n log V) total groups.
template <class Int>
std::vector<std::vector<std::pair<Int, std::uint64_t>>>
subarray_gcd_suffix_groups(const std::vector<Int> &vs) {
  static_assert(std::is_integral_v<Int>);
  std::vector<std::vector<std::pair<Int, std::uint64_t>>> res;
  res.reserve(vs.size());
  std::vector<std::pair<Int, std::uint64_t>> pre;
  for (Int val : vs) {
    std::vector<std::pair<Int, std::uint64_t>> cur;
    auto app = [&](Int div, std::uint64_t cnt) {
      if (!cur.empty() && cur.back().first == div) {
        cur.back().second += cnt;
      } else {
        cur.emplace_back(div, cnt);
      }
    };
    app(std::abs(val), 1);
    for (auto [div, cnt] : pre) {
      app(std::gcd(div, val), cnt);
    }
    res.push_back(cur);
    pre = std::move(cur);
  }
  return res;
}

/// @brief Count subarrays by their gcd; returned pairs are sorted by gcd.
template <class Int>
std::vector<std::pair<Int, std::uint64_t>>
subarray_gcd_counts(const std::vector<Int> &vs) {
  std::map<Int, std::uint64_t> cou;
  for (const auto &gro : subarray_gcd_suffix_groups(vs)) {
    for (auto [div, cnt] : gro) {
      cou[div] += cnt;
    }
  }
  return {cou.begin(), cou.end()};
}

} // namespace noya

#endif // NOYA_SUBARRAY_GCD_HPP
#include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <map>
#include <numeric>
#include <type_traits>
#include <utility>
#include <vector>

/// @complexity Time: O(n log A).
/// Space: O(log A) frontier per endpoint, excluding aggregate output.

namespace noya {

/// @brief For every right endpoint, group all nonempty suffixes by gcd in
/// O(n log V) total groups.
template <class Int>
std::vector<std::vector<std::pair<Int, std::uint64_t>>>
subarray_gcd_suffix_groups(const std::vector<Int> &vs) {
  static_assert(std::is_integral_v<Int>);
  std::vector<std::vector<std::pair<Int, std::uint64_t>>> res;
  res.reserve(vs.size());
  std::vector<std::pair<Int, std::uint64_t>> pre;
  for (Int val : vs) {
    std::vector<std::pair<Int, std::uint64_t>> cur;
    auto app = [&](Int div, std::uint64_t cnt) {
      if (!cur.empty() && cur.back().first == div) {
        cur.back().second += cnt;
      } else {
        cur.emplace_back(div, cnt);
      }
    };
    app(std::abs(val), 1);
    for (auto [div, cnt] : pre) {
      app(std::gcd(div, val), cnt);
    }
    res.push_back(cur);
    pre = std::move(cur);
  }
  return res;
}

/// @brief Count subarrays by their gcd; returned pairs are sorted by gcd.
template <class Int>
std::vector<std::pair<Int, std::uint64_t>>
subarray_gcd_counts(const std::vector<Int> &vs) {
  std::map<Int, std::uint64_t> cou;
  for (const auto &gro : subarray_gcd_suffix_groups(vs)) {
    for (auto [div, cnt] : gro) {
      cou[div] += cnt;
    }
  }
  return {cou.begin(), cou.end()};
}

} // namespace noya