Автор задачі: | Mohammad Nasser (MOAGEZA) |
Підготував: | Mohammad Nasser (MOAGEZA) |
Редактор: | Hasan Saleh (MathModel) |
Розв'язання
Загальна ідея:
Елемент a_i є несумісним з , якщо в ньому встановлено біт, якого немає в — формально, якщо (a_i \,\&\, \sim k) \neq 0, тобто a_i має принаймні один біт, який дорівнює в a_i, але в . Такий елемент ніколи не може бути частиною підмасиву, OR якого дорівнює , тому його потрібно видалити. Замінімо кожен несумісний елемент на і запишемо його позицію в масив префіксних сум , щоб \mathit{sum}[r] - \mathit{sum}[l-1] давало кількість видалень, потрібних на відрізку [l, r].
Після занулення несумісних елементів побудуємо sparse table на зміненому масиві, щоб відповідати на запити OR на відрізку за .
Крок 1 — Мінімальна кількість видалень:
Для кожної лівої межі виконаємо бінарний пошук найменшої правої межі , такої що \mathrm{OR}(i, r) = k. Вартість вікна дорівнює \mathit{sum}[r] - \mathit{sum}[i-1]. Візьмемо мінімум за всіма коректними вікнами:
Якщо жодне вікно ніколи не досягає OR , виводимо -1 -1.
Крок 2 — Максимальна довжина:
Для кожної лівої межі виконаємо бінарний пошук найбільшої правої межі , такої що кількість видалень на не перевищує і \mathrm{OR}(i, r) = k. Ефективна довжина отриманого підмасиву (після видалень) дорівнює (r - i + 1) - \mathit{ans}. Візьмемо максимум за всіма коректними вікнами:
Розв'язок працює за \mathcal{O}\!\left(n \log n + \sum n\right) часу на один вхідний файл, де доданок n \log n виникає через побудову sparse table і два проходи бінарного пошуку.
#include <bits/stdc++.h>
#define ll long long
#define rv return void
#define vec vector
#define Moageza ios::sync_with_stdio(false);cout.tie(NULL);cin.tie(NULL);
using namespace std;
const int N = 2e5 + 5;
int n, k, a[N], T[N][22], Log[N];
int merge(int a, int b) { return (a | b); }
void build() {
for (int i = 1; i <= n; i++) T[i][0] = a[i];
for (int pw = 1; (1 << pw) <= n; pw++)
for (int i = 1; i + (1 << pw) - 1 <= n; i++)
T[i][pw] = merge(T[i][pw-1], T[i+(1<<(pw-1))][pw-1]);
}
int query(int l, int r) {
int pw = Log[r - l + 1];
return merge(T[l][pw], T[r-(1<<pw)+1][pw]);
}
void preCount() {
Log[1] = 0;
for (int i = 2; i < N; i++) Log[i] = Log[i >> 1] + 1;
}
void solve() {
cin >> n >> k;
for (int i = 1; i <= n; i++) cin >> a[i];
vec<int> sum(n + 1, 0);
for (int i = 1; i <= n; i++) {
bitset<30> f = a[i], s = k;
bool bad = false;
for (int j = 0; j < 30; j++)
if (f[j] && !s[j]) bad = true;
if (bad) { a[i] = 0; sum[i] = 1; }
}
for (int i = 1; i <= n; i++) sum[i] += sum[i-1];
build();
int ans = 1e9, len = 0;
for (int i = 1; i <= n; i++) {
int l = i, r = n;
while (l <= r) {
int mid = (l + r) / 2;
if (query(i, mid) == k) {
ans = min(ans, sum[mid] - sum[i-1]);
r = mid - 1;
} else l = mid + 1;
}
}
if (ans == (int)1e9) rv(cout << "-1 -1");
for (int i = 1; i <= n; i++) {
int l = i, r = n;
while (l <= r) {
int mid = (l + r) / 2;
if (sum[mid] - sum[i-1] <= ans) {
l = mid + 1;
if (query(i, mid) == k)
len = max(len, (mid - i + 1) - ans);
} else r = mid - 1;
}
}
cout << ans << " " << len;
}
signed main() {
Moageza
preCount();
int t; cin >> t;
while (t--) { solve(); cout << "\n"; }
return 0;
}