Swapity Swap
Solución en video
Por David Li
Video de YouTube (LrcugMyMFyQ)
Código de la solución en video
#include <iostream>
using namespace std;
void setIO(string s) {
ios_base::sync_with_stdio(0);
cin.tie(0);
freopen((s + ".in").c_str(), "r", stdin);
freopen((s + ".out").c_str(), "w", stdout);
}
int N, K, A1, A2, B1, B2, res[101]; // res guarda el resultado
int nex(int x) {
if (A1 <= x && x <= A2) // simulamos el paso 1
x = A1 + A2 - x;
if (B1 <= x && x <= B2) // simulamos el paso 2
x = B1 + B2 - x;
return x;
}
int main() {
setIO("swap");
// leemos la entrada
cin >> N >> K >> A1 >> A2 >> B1 >> B2;
// resolvemos para cada vaca
for (int i = 1; i <= N; ++i) {
// p = ¿cuántos turnos llevamos?
// cur = ¿dónde estamos después de p turnos?
int p = 1, cur = nex(i);
while (cur != i) { // seguimos hasta haber encontrado un ciclo
p++;
cur = nex(cur); // simulamos otro turno
}
int k = K % p; // reducimos k
for (int j = 0; j < k; ++j) cur = nex(cur);
res[cur] = i; // la posición de la vaca i después de k pasos es cur
}
// imprimimos la respuesta
for (int i = 1; i <= N; ++i) cout << res[i] << "\n";
}import java.io.*;
import java.util.*;
public class swap {
static int A1, A2, B1, B2;
public static void main(String[] args) throws IOException {
// leemos la entrada
BufferedReader br = new BufferedReader(new FileReader(new File("swap.in")));
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int K = Integer.parseInt(st.nextToken());
st = new StringTokenizer(br.readLine());
A1 = Integer.parseInt(st.nextToken());
A2 = Integer.parseInt(st.nextToken());
st = new StringTokenizer(br.readLine());
B1 = Integer.parseInt(st.nextToken());
B2 = Integer.parseInt(st.nextToken());
int[] res = new int[N + 1];
// resolvemos para cada vaca
for (int i = 1; i <= N; ++i) {
// p = ¿cuántos turnos llevamos?
// cur = ¿dónde estamos después de p turnos?
int p = 1, cur = nex(i);
while (cur != i) { // seguimos hasta haber encontrado un ciclo
p++;
cur = nex(cur); // simulamos otro turno
}
int k = K % p; // reducimos k
for (int j = 0; j < k; ++j) cur = nex(cur);
res[cur] = i; // la posición de la vaca i después de k pasos es cur
}
PrintWriter out = new PrintWriter("swap.out");
for (int i = 1; i <= N; i++) { out.println(res[i]); }
out.close();
}
public static int nex(int x) { // simula un turno, o dos pasos
if (A1 <= x && x <= A2) x = A1 + A2 - x;
if (B1 <= x && x <= B2) x = B1 + B2 - x;
return x;
}
}Pista 1
Intentemos simular los intercambios nosotros mismos sobre la entrada de ejemplo. ¿Qué se observa sobre el desplazamiento de ciertas vacas?
Respuesta a la pista 1
¡Después de un cierto número de ciclos, las vacas terminan justo donde empezaron!
Pista 2
Dado que las vacas solo dan vueltas en ciclos a lo largo de todos estos intercambios, ¿se puede pensar en una forma más eficiente de simularlos?
Solución
Explicación
Para obtener el puntaje completo, necesitamos hacer algo mejor que simular los procesos uno tras otro.
Notamos que, después de repetir el proceso un cierto número de veces, las vacas terminan todas justo donde empezaron. Nótese que cada vaca solo puede intercambiarse a un número finito de nuevas posiciones después de cada proceso, así que debe volver a su posición original para arbitrariamente grande. Esto nos da la idea de simular el proceso de intercambio hasta que todas las vacas vuelvan a sus posiciones originales.
Sea el número mínimo de veces que debemos repetir el proceso para que esto ocurra. Para hallar , podemos llevar la cuenta del ordenamiento de las vacas, y si alguna vez encontramos un ordenamiento guardado previamente, usamos el número de ordenamientos guardados para determinar .
Ahora solo tenemos que considerar el resto de al dividirlo por en lugar de mismo. Se puede verificar por búsqueda exhaustiva que el valor máximo posible de para es . Así, las cotas son lo bastante pequeñas como para que podamos simular el proceso veces y aun así pasar el problema a tiempo.
Implementación
Complejidad temporal:
#include <fstream>
#include <iostream>
#include <numeric>
#include <set>
#include <vector>
using std::cout;
using std::endl;
using std::vector;
/** Invierte [start, end] en el vector dado in-place. */
template <typename T> void reverse_segment(vector<T> &vec, int start, int end) {
while (start < end) {
T temp = vec[start];
vec[start] = vec[end];
vec[end] = temp;
start++;
end--;
}
}
int main() {
std::ifstream read("swap.in");
int n, k;
read >> n >> k;
int a1, a2;
int b1, b2;
read >> a1 >> a2 >> b1 >> b2;
vector<int> cows(n);
// Asignamos los valores 1, 2, 3... al vector de vacas
iota(cows.begin(), cows.end(), 1);
// Aplicamos intercambios hasta que las vacas se repitan
std::set<vector<int>> visited{cows};
while (true) {
reverse_segment(cows, a1 - 1, a2 - 1);
reverse_segment(cows, b1 - 1, b2 - 1);
if (visited.count(cows)) { break; }
visited.insert(cows);
}
int cycle_len = visited.size();
int swaps_left = k % cycle_len;
for (int s = 0; s < swaps_left; s++) {
reverse_segment(cows, a1 - 1, a2 - 1);
reverse_segment(cows, b1 - 1, b2 - 1);
}
std::ofstream written("swap.out");
for (int c : cows) { written << c << '\n'; }
}import java.io.*;
import java.util.*;
public class Swap {
public static void main(String[] args) throws IOException {
BufferedReader read = new BufferedReader(new FileReader("swap.in"));
StringTokenizer st = new StringTokenizer(read.readLine());
int n = Integer.parseInt(st.nextToken());
int k = Integer.parseInt(st.nextToken());
st = new StringTokenizer(read.readLine());
int a1 = Integer.parseInt(st.nextToken()) - 1;
int a2 = Integer.parseInt(st.nextToken()) - 1;
st = new StringTokenizer(read.readLine());
int b1 = Integer.parseInt(st.nextToken()) - 1;
int b2 = Integer.parseInt(st.nextToken()) - 1;
read.close();
List<Integer> cows = new ArrayList<>();
for (int c = 1; c <= n; c++) { cows.add(c); }
// Aplicamos intercambios hasta que las vacas se repitan
Set<List<Integer>> visited = new HashSet<>();
visited.add(new ArrayList<>(cows));
while (true) {
reverseSegment(cows, a1, a2);
reverseSegment(cows, b1, b2);
if (visited.contains(cows)) { break; }
visited.add(new ArrayList<>(cows));
}
int cycleLen = visited.size();
int swapsLeft = k % cycleLen;
for (int s = 0; s < swapsLeft; s++) {
reverseSegment(cows, a1, a2);
reverseSegment(cows, b1, b2);
}
PrintWriter written = new PrintWriter("swap.out");
for (int c : cows) { written.println(c); }
written.close();
}
/** Invierte [start, end] en la lista dada in-place. */
static <T> void reverseSegment(List<T> lst, int start, int end) {
while (start < end) {
T temp = lst.get(start);
lst.set(start, lst.get(end));
lst.set(end, temp);
start++;
end--;
}
}
}from typing import List
def reverse_segment(lst: List[int], start: int, end: int):
"""Invierte [start, end] en la lista dada in-place."""
while start < end:
lst[start], lst[end] = lst[end], lst[start]
start += 1
end -= 1
with open("swap.in") as read:
n, k = map(int, read.readline().split())
a1, a2 = map(int, read.readline().split())
b1, b2 = map(int, read.readline().split())
cows = list(range(1, n + 1))
# Aplicamos intercambios hasta que las vacas se repitan
visited = set()
visited.add(tuple(cows))
while True:
reverse_segment(cows, a1 - 1, a2 - 1)
reverse_segment(cows, b1 - 1, b2 - 1)
if tuple(cows) in visited:
break
visited.add(tuple(cows))
cycle_len = len(visited)
swaps_left = k % cycle_len
for _ in range(swaps_left):
reverse_segment(cows, a1 - 1, a2 - 1)
reverse_segment(cows, b1 - 1, b2 - 1)
print(*cows, sep="\n", file=open("swap.out", "w"))