【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\) 成立。
核心思路:
- 先用 ST 表预处理出所有(静态)区间 gcd;
- 在第 1 步的基础上,遍历数组 \(a\),枚举以 \(a_i\) 为最大公因数的区间,使用二分法维护出区间的左右端点;
- 在第 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;
}
浙公网安备 33010602011771号