Medical Parity
Explicación
Nótese que es simplemente el XOR de los primeros bits de . Por la naturaleza acumulativa de la operación, invertir el bit de invierte todos los bits de en . Por lo tanto, podemos tratar una inversión de bit en como invertir un rango sufijo en , y manipular solo para que coincida con un esperado, el valor- que produce tal cual. El problema pasa a ser manipular de una de las siguientes formas para que coincida con :
- Invertir el rango continuo de dígitos .
- Invertir un solo dígito .
Por simplicidad, transformamos el problema en otro en el que el arreglo esperado es todo . Lo hacemos tomando , y como solo importan las diferencias entre el arreglo objetivo y el de origen, el problema es equivalente a transformar un arreglo de s en .
Ahora consideramos la Operación 1. Como las operaciones son todas desde el final, nos inspiramos en las sumas de prefijos para operar sobre un rango arbitrario con operaciones: Nótese que se puede invertir cualquier rango invirtiendo el rango y luego el rango . Esto produce un bloque de s si el rango no se había operado antes. Esto requiere operaciones, excepto cuando , en cuyo caso solo hace falta operación: invertir . La cantidad de operaciones se puede tratar como la cantidad de “transiciones” en al recorrerlo de izquierda a derecha, con un valor artificial -ésimo insertado en (de modo que, si el primer valor es , se considera una transición adicional).
La Operación 2 permite cambiar un solo dígito de a partir de una construcción que usa solo la Operación 1. Nótese que, al invertir al menos elementos adyacentes, siempre es más óptimo usar a lo sumo Operaciones 1 que invertirlos uno por uno con al menos Operaciones 2. La única optimización que aporta la Operación 2 es, por lo tanto, reducir la cantidad de transiciones de la estrategia con Operación 1 invirtiendo elementos sueltos distintos de ambos vecinos, lo que combina las dos transiciones adyacentes en inversión.
Primero calculamos y armamos un arreglo con los índices de todas las transiciones; luego, si las posiciones de dos transiciones están a distancia , reducimos el conteo de operaciones en porque podemos usar la Operación 2 para invertir el elemento suelto y eliminar la transición.
Implementación
Complejidad temporal:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
int test_num;
cin >> test_num;
for (int t = 0; t < test_num; t++) {
string x_prime, y_prime;
cin >> x_prime >> y_prime;
int n = x_prime.length();
// Indexamos los vectores desde 1 para el 0 centinela inicial al contar.
vector<bool> d(n + 1);
// El valor dinámico de z_i, el arreglo esperado que produce x'.
bool z_i = 0;
for (int i = 0; i < n; i++) {
// -'0' convierte el dígito ASCII en entero. ^= equivale a
// sumar y tomar módulo 2
z_i ^= x_prime[i] - '0';
// Calculamos el XOR con b para obtener la diferencia; lo guardamos en el índice i+1 porque
// nuestra DP empieza en 1.
d[i + 1] = z_i ^ (y_prime[i] - '0');
}
vector<int> transitions;
for (int i = 1; i <= n; i++) {
if (d[i] != d[i - 1]) transitions.push_back(i);
}
int ans = transitions.size();
// Emparejamos transiciones adyacentes y restamos 1 a la respuesta por el reemplazo
// con la Operación 2
for (int i = 0; i + 1 < (int)transitions.size();) {
if (transitions[i + 1] == transitions[i] + 1) {
ans--;
i += 2;
} else {
i++;
}
}
cout << ans << endl;
}
return 0;
}