Автор задачі: | Матвій Грицина |
Підготували: | Матвій Грицина, Констянтин Денисов |
Розбір: | Матвій Грицина |
Ідея
Введемо масив — найбільший серед усіх мінімальних лівих індексів трійок, де є правим елементом. Тобто \text{lft}[k] = i, де (i,j,k) — деяка валідна трійка і найбільший індекс з усіх валідних трійок, які мають правий індекс . Також для кожного такого зберігаємо масив \text{ans}[k] = (j,k) — конкретну пару індексів, що утворює валідну трійку разом із . Причому зі всіх таких пар зберігаємо ту, у якої значення — найменше.
Також побудуємо масив , де
Тоді для запиту (l,r) відповідь існує тоді і тільки тоді, коли \text{pref\_max}[r] \ge l.
Як обчислити масив
Проходимо по масиву зліва направо. Для кожного підтримуємо масив його простих дільників. Також підтримуємо для кожного простого два останніх індекси, де ділить :
— найближчий попередній індекс;
— передостанній попередній індекс.
\text{lst}[i][p] = -1, якщо такого індекса не існує.
Розглянемо два випадки.
Випадок 1: НСД всіх трьох чисел
В такому випадку має спільний простий дільник як з , так і з . Переберемо , і якщо \text{lst}[1][p] \neq -1, тобто зліва від індекса існує хоча б два числа, які діляться на , оновлюємо
Випадок 2: НСД трьох чисел
Припустимо, що має спільний простий дільник з та спільний простий дільник з . В такому випадку ми можемо взяти для кожного простого і перевірити, чи НСД чисел на цих позиціях більший за . Тобто якщо
і
тоді ми оновлюємо
Як відповідати на запити
Для того щоб відповідь на запит (l,r) існувала, для якогось l \le k \le r має виконуватись умова \text{lft}[k] \ge l. Іншими словами, відповідь існує тоді і тільки тоді, коли
Оскільки для k < l маємо \text{lft}[k] < l, замість максимуму на відрізку можна брати максимум на префіксі. Тоді нехай idx = \text{pref\_max}[r]. Якщо idx < l, то відповіді не існує, інакше в якості трійки можна взяти
Асимптотика
За допомогою решета Ератосфена можна передрахувати всі прості дільники для чисел \le A = 2 \cdot 10^5 за O(A \log A). Обчислюємо масив за O(n d^2 \log A), де — максимальна кількість простих дільників у числа. При заданих обмеженнях d \le 6, тому це легко вкладається в обмеження. Відповідаємо на кожен запит за .
Отже маємо O(A \log A + n d^2 \log A + q).
#include <bits/stdc++.h>
using namespace std;
const int MAXA = 200010;
const int MAXN = 400000;
vector<int> primes[MAXA];
void sieve() {
for (int i = 2; i <= MAXA; i++)
if (primes[i].empty()) {
for (int j = i; j < MAXA; j += i)
primes[j].push_back(i);
}
}
int main() {
sieve();
int n;
cin >> n;
vector<int> a(n);
for (auto& ai : a)
cin >> ai;
vector<pair<int, int>> ans(n, {-1, -1});
vector<int> pref_max(n + 1, -1), lft(n, -1);
vector<vector<int>> lst(2, vector<int>(MAXA, -1));
for (int i = 0; i < n; i++) {
int x = a[i];
for (auto p : primes[x])
if (lst[1][p] != -1) {
lft[i] = max(lft[i], lst[1][p]);
if (ans[lst[1][p]].first == -1)
ans[lst[1][p]] = {lst[0][p], i};
}
for (auto p1 : primes[x])
for (auto p2 : primes[x]) {
if (p1 == p2 || lst[0][p1] == lst[0][p2])
continue;
if (lst[0][p1] >= 0 && lst[0][p2] >= 0 &&
__gcd(a[lst[0][p1]], a[lst[0][p2]]) > 1 &&
min(lst[0][p1], lst[0][p2]) > lft[i]) {
lft[i] = min(lst[0][p1], lst[0][p2]);
if (ans[min(lst[0][p1], lst[0][p2])].first == -1)
ans[min(lst[0][p1], lst[0][p2])] =
{max(lst[0][p1], lst[0][p2]), i};
}
}
for (auto p : primes[x]) {
lst[1][p] = lst[0][p];
lst[0][p] = i;
}
}
for (int i = 1; i < n; i++)
pref_max[i] = max(pref_max[i - 1], lft[i]);
int q;
cin >> q;
while (q--) {
int l, r;
cin >> l >> r;
--l, --r;
int idx = pref_max[r];
if (idx < l) {
cout << -1 << '\n';
} else {
cout << ans[idx].first + 1 << ' '
<< ans[idx].second + 1 << ' '
<< idx + 1 << '\n';
}
}
}