Editorial for AND-Magedón
Submitting an official solution before solving the problem yourself is a bannable offence.
Author:
Problema:
Dada una secuencia de tamaño
y un entero no negativo
. Calcular el valor máximo de
, donde
es una subsecuencia de
de tamaño
.
Soluciones
Subtarea 1: 
La subsecuencia tiene un solo elemento, por lo tanto, el operador dará como resultado el mismo número. La respuesta es el máximo elemento de la secuencia. Complejidad:
.
#include <iostream>
#include <vector>
#include <algorithm>
#include <limits>
using namespace std;
int main() {
int T; // Número de casos de prueba
cin >> T;
while (T--) {
int N, K;
cin >> N;
cin >> K;
vector<long long> A(N);
for (int i = 0; i < N; i++) {
cin >> A[i];
}
if (K == 1) {
cout << *max_element(A.begin(), A.end()) << endl;
}
}
return 0;
}
Subtarea 2:
y 
La subsecuencia tiene dos elementos, como , se pueden probar todos los pares de elementos. Complejidad:
.
#include <iostream>
#include <vector>
#include <algorithm>
#include <limits>
using namespace std;
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T; // Número de casos de prueba
cin >> T;
while (T--) {
int N, K;
cin >> N;
cin >> K;
vector<long long> A(N);
for (int i = 0; i < N; i++) {
cin >> A[i];
}
if (K == 1) {
cout << *max_element(A.begin(), A.end()) << endl;
}
else if(K == 2){
long long max_val = 0;
for (int i = 0; i < N; i++) {
for (int j = i + 1; j < N; j++) {
max_val = max(max_val, A[i] & A[j]);
}
}
cout << max_val << endl;
}
}
return 0;
}
Subtarea 3: 
Como , se pueden probar todos las subsecuencias de elementos de tamaño
, usando una máscara de bits. Complejidad:
.
#include <iostream>
#include <vector>
#include <algorithm>
#include <limits>
using namespace std;
long long maxAndSubsequence(const vector<long long>& A, int K) {
int N = A.size();
long long max_val = 0;
// Generar todas las posibles subsecuencias de tamaño K usando una máscara de bits
for (int mask = 0; mask < (1 << N); mask++) {
vector<long long> subseq;
for (int i = 0; i < N; i++) {
if (mask & (1 << i)) {
subseq.push_back(A[i]);
}
}
if (subseq.size() == K) {
long long and_val = subseq[0];
for (int j = 1; j < K; j++) {
and_val &= subseq[j];
}
max_val = max(max_val, and_val);
}
}
return max_val;
}
int main() {
int T; // Número de casos de prueba
cin >> T;
while (T--) {
int N, K;
cin >> N;
cin >> K;
vector<long long> A(N);
for (int i = 0; i < N; i++) {
cin >> A[i];
}
cout << maxAndSubsequence(A, K) << endl;
}
return 0;
}
Subtarea 4: 
Como , se pueden probar todos las subsecuencias de elementos de tamaño
(una posible implementación sería usar recursividad donde en cada nivel de la recursividad tomar un elemento nuevo). Complejidad:
.
#include <iostream>
#include <vector>
#include <algorithm>
#include <limits>
using namespace std;
void findSubsequences(const vector<long long>& A, int K, int index, vector<long long>& current, long long& max_val) {
if (current.size() == K) {
long long and_val = current[0];
for (int i = 1; i < K; i++) {
and_val &= current[i];
}
max_val = max(max_val, and_val);
return;
}
if (index == A.size()) {
return;
}
current.push_back(A[index]);
findSubsequences(A, K, index + 1, current, max_val);
current.pop_back();
findSubsequences(A, K, index + 1, current, max_val);
}
long long maxAndSubsequence(const vector<long long>& A, int K) {
long long max_val = 0;
vector<long long> current;
findSubsequences(A, K, 0, current, max_val);
return max_val;
}
int main() {
int T; // Número de casos de prueba
cin >> T;
while (T--) {
int N, K;
cin >> N;
cin >> K;
vector<long long> A(N);
for (int i = 0; i < N; i++) {
cin >> A[i];
}
cout << maxAndSubsequence(A, K) << endl;
}
return 0;
}
Subtarea 5: Todos los elementos de
son potencias de
.
Observación 1: Sea la respuesta al problema. Para que
en su representación binaria tenga encendido el
ésimo bit, los
elementos deben tener encendido ese bit.
Como los números son potencias de , solo se puede tener encendido un bit a la vez.
será la mayor potencia de
que aparezca al menos
veces.
Solución 1: Llevar un arreglo de frecuencia para cada potencia. Complejidad: .
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main() {
int T; // Número de casos de prueba
cin >> T;
while (T--) {
int N, K;
cin >> N;
cin >> K;
vector<long long> A(N);
for (int i = 0; i < N; i++) {
cin >> A[i];
}
// Llevar un arreglo de frecuencia para cada potencia de 2
map<long long, int> frequency;
for (int i = 0; i < N; i++) {
frequency[A[i]]++;
}
long long ans = 0;
for (const auto& [value, count] : frequency) {
if (count >= K) {
ans = max(ans, value);
}
}
cout << ans << endl;
}
return 0;
}
Solución 2: Contar para cada potencia de las ocurrencias. Complejidad:
.
Subtarea 6: Sin restricciones adicionales.
Observación 2: Sea el mayor bit que puede tener encendido
dado una secuencia
.
siempre tendrá ese bit encendido, dado que si encendemos todos los bits menores que
, seguirá siendo menor que
.
Por lo visto en las observaciones 1 y 2, se puede llegar a la siguiente recurrencia, sea como la respuesta usando solamente los primeros
bits tomando elementos de la secuencia
.
se dividirá en dos casos:
- Se puede encender el
ésimo bit. En ese caso, la respuesta será
, donde
representa la subsecuencia formada por todos los elementos de
que tienen el
ésimo bit encendido.
- No se puede encender el
ésimo bit. En ese caso, la respuesta será
.
Complejidad:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
long long findMaxAns(int bit, const vector<long long>& A, int K) {
if (bit < 0) {
return 0;
}
vector<long long> A_prime;
for (long long num : A) {
if (num & (1LL << bit)) {
A_prime.push_back(num);
}
}
if (A_prime.size() >= K) {
return (1LL << bit) | findMaxAns(bit - 1, A_prime, K);
} else {
return findMaxAns(bit - 1, A, K);
}
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T; // Número de casos de prueba
cin >> T;
while (T--) {
int N, K;
cin >> N;
cin >> K;
vector<long long> A(N);
for (int i = 0; i < N; i++) {
cin >> A[i];
}
long long ans = findMaxAns(60, A, K);
cout << ans << endl;
}
return 0;
}
Implementación iterativa de la idea anterior:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#pragma GCC optimize("O3")
#define x first
#define y second
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
ll t;
cin >> t;
while (t--) {
ll n, k;
cin >> n >> k;
vector<ll> cad(n);
for (int i = 0; i < n; i++) {
cin >> cad[i];
}
ll ans = 0;
for (int i = 59; i > -1; i--) {
ll c = 0;
ll t1 = (1LL << i);
for (int j = 0; j < n; j++) {
if ((t1 & cad[j]) != 0 && (cad[j] & ans) == ans) {
c++;
if (c == k) break;
}
}
if (c >= k) {
ans += t1;
}
}
cout << ans << "\n";
}
}
Nota: Todos los códigos excepto el último fueron generados a partir de la editorial con Copilot.
Comments