• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

RomanLin

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

【ST表+二分】codeforces 359 D. Pair of Numbers

题目

https://codeforces.com/problemset/problem/359/D

题解

假设数组 \(a = a_1,a_2,...,a_l,...,a_i,...,a_r,...,a_n\),且 \(a_l,a_{l+1},...,a_i,...,a_r (l \leq a_i \leq r)\) 每个数都满足能被 \(a_i\) 整除,那么 \(gcd(a_l,a_{l+1},...a_i,...,a_r) = a_i\) 成立。

核心思路:

  1. 先用 ST 表预处理出所有(静态)区间 gcd;
  2. 在第 1 步的基础上,遍历数组 \(a\),枚举以 \(a_i\) 为最大公因数的区间,使用二分法维护出区间的左右端点;
  3. 在第 2 步维护出所有区间的基础上,维护出区间最大长度,然后筛选出长度为最大长度的所有区间即可。

参考代码

#include<iostream>
#include<vector>
#include<queue>
#include<cmath>
#include<numeric>

using ll = long long;

template<typename T, typename E, typename F>
class SparseTable {/*稀疏表*/
private:
    std::vector<std::vector<E>> dp;
    F func;
public:
    SparseTable(T& arr, int arr_size, F func): func(func) {
        int log2_arr_size = log2(arr_size) + 1;
        dp.assign(arr_size, std::vector<E>(log2_arr_size));
        for (int i = 0; i < arr_size; ++ i) dp[i][0] = arr[i];// 初始化第一层
        for (int j = 1; j < log2_arr_size; ++ j) {// 枚举区间长度 2^j
            int step = 1 << j;// 区间长度
            for (int i = 0; i + step - 1 < arr_size; ++ i) {// 枚举区间起点
                dp[i][j] = func(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
            }
        }
    }

    E query(int l, int r) {// 下标从 0 开始
        int k = log2(r - l + 1);
        return func(dp[l][k], dp[r - (1 << k) + 1][k]);
    }
};

// 通用工厂函数
template<typename T, typename E, typename Func>
auto makeSparseTable(T& arr, int arr_size, Func op) {
    return SparseTable<T, E, Func>(arr, arr_size, op);
}

// 专门的MAX工厂
template<typename T, typename E>
auto makeSparseTableWithMax(T& arr, int arr_size) {
    auto max_op = [](E a, E b) -> E { return std::max(a, b); };
    return makeSparseTable<T, E, decltype(max_op)>(arr, arr_size, max_op);
}

// 专门的MIN工厂
template<typename T, typename E>
auto makeSparseTableWithMin(T& arr, int arr_size) {
    auto min_op = [](E a, E b) -> E { return std::min(a, b); };
    return makeSparseTable<T, E, decltype(min_op)>(arr, arr_size, min_op);
}

// 专门的GCD工厂
template<typename T, typename E>
auto makeSparseTableWithGcd(T& arr, int arr_size) {
    auto gcd_op = [](E a, E b) { return std::gcd(a, b); };
    return makeSparseTable<T, E, decltype(gcd_op)>(arr, arr_size, gcd_op);
}

// 专门的LCM工厂
template<typename T, typename E>
auto makeSparseTableWithLcm(T& arr, int arr_size) {
    auto lcm_op = [](E a, E b) { return std::lcm(a, b); };
    return makeSparseTable<T, E, decltype(lcm_op)>(arr, arr_size, lcm_op);
}

// 专门按位与工厂
template<typename T, typename E>
auto makeSparseTableWithBitwiseAnd(T& arr, int arr_size) {
    return makeSparseTable<T, E, std::bit_and<E>>(arr, arr_size, std::bit_and<E>{});
}

// 专门按位或工厂
template<typename T, typename E>
auto makeSparseTableWithBitwiseOr(T& arr, int arr_size) {
    return makeSparseTable<T, E, std::bit_or<E>>(arr, arr_size, std::bit_or<E>{});
}

int main() {
    std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout.tie(nullptr);
    int n, dis = 0;
    std::cin >> n;
    std::vector<int> a(n);
    std::queue<ll> que;
    for (int i = 0; i < n; ++ i) std::cin >> a[i];
    SparseTable st = makeSparseTableWithGcd<std::vector<int>, int>(a, n);
    for (int i = 0; i < n; ++ i) {
        int le = 0, ri = i, md, l, r;
        while (le < ri) {
            md = le + ri >> 1;
            if (a[i] == st.query(md, i)) ri = md;
            else le = md + 1;
        }
        l = le, le = i, ri = n - 1;
        while (le < ri) {
            md = le + ri + 1 >> 1;
            if (a[i] == st.query(i, md)) le = md;
            else ri = md - 1;
        }
        r = le;
        if (r - l > dis) {
            que = std::queue<ll>();
            que.push(1LL * r * n + l);
            dis = r - l;
        } else if (que.empty() || r - l == dis && 1LL * r * n + l != que.back()) que.push(1LL * r * n + l);
    }
    std::cout << que.size() << ' ' << dis << '\n';
    while (!que.empty()) {
        std::cout << (que.front() % n + 1) << ' ';
        que.pop();
    }
    return 0;
}

posted on 2026-01-24 16:32  RomanLin  阅读(2)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3