Taming the Herd
Esta solución es , más rápida que la del editorial oficial, pero no es necesaria ya que .
Explicación
Sea el número mínimo de cambios que se deben hacer en las primeras entradas para que haya fugas entre las primeras entradas.
Hay tres casos cuando calculamos el valor actual de :
-
Si el registro fue alterado y las vacas NO se fugarían:
- Comparado con el día anterior, el número de fugas no cambia. Sin embargo, necesitamos un cambio más del registro, así que transferimos desde .
-
Si el registro fue alterado y las vacas se fugarían (nótese que ):
- Comparado con el día anterior, el número de fugas aumenta en 1. También necesitamos un cambio más del registro, así que transferimos desde .
-
Si el registro NO fue alterado:
- Entonces la -ésima fuga sería en el -ésimo día, así que transferimos desde . \texttt{dp}[i][j] = \texttt{dp}[i-1][j-a[j]-1]+\texttt{range\\_ans}[j-a[j]][j]);
\texttt{range\\_ans}[l][r] representa el costo mínimo de reemplazar el rango por .
Así, nuestra relación de DP final es
\texttt{dp}[i][j] = \min\begin{cases} \texttt{dp}[i][j-1]+1\\ \texttt{dp}[i-1][j-1]+1\\ \texttt{dp}[i-1][j-a[j]-1] + \texttt{range\\_ans}[j-a[j]][j]) \end{cases}Nótese que si los índices están fuera de rango, el valor no se considera.
Implementación
Complejidad temporal:
#include <bits/stdc++.h>
using namespace std;
int main() {
freopen("taming.in", "r", stdin);
freopen("taming.out", "w", stdout);
int n;
cin >> n;
vector<int> entry(n);
for (int i = 0; i < n; i++) { cin >> entry[i]; }
vector<vector<int>> range_ans(n, vector<int>(n));
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
if (j) {
range_ans[i][j] = range_ans[i][j - 1] + (entry[j] == j - i ? 0 : 1);
} else {
range_ans[i][j] = (entry[j] == j - i ? 0 : 1);
}
}
}
vector<vector<int>> dp(n + 1, vector<int>(n, INT32_MAX));
for (int i = 1; i <= n; i++) {
for (int j = i - 1; j < n; j++) {
if (!j) {
if (entry[j] == 0) {
dp[i][j] = 0;
} else {
dp[i][j] = 1;
}
continue;
}
// Case 1
if (dp[i][j - 1] != INT32_MAX) { dp[i][j] = dp[i][j - 1] + 1; }
// Case 2
if (entry[j] && dp[i - 1][j - 1] != INT32_MAX) {
dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + 1);
}
// Case 3
if (j - entry[j] - 1 >= 0 && dp[i - 1][j - entry[j] - 1] != INT32_MAX) {
dp[i][j] = min(dp[i][j], dp[i - 1][j - entry[j] - 1] +
range_ans[j - entry[j]][j]);
}
if (j - entry[j] == 0 && i == 1) {
dp[i][j] = min(dp[i][j], range_ans[j - entry[j]][j]);
}
}
}
for (int i = 1; i <= n; i++) { cout << dp[i][n - 1] << endl; }
}with open("taming.in", "r") as read:
n = int(read.readline().strip())
entry = list(map(int, read.readline().strip().split()))
range_ans = [[0] * n for _ in range(n)]
for i in range(n):
for j in range(i, n):
if j > 0:
range_ans[i][j] = range_ans[i][j - 1] + (0 if entry[j] == j - i else 1)
else:
range_ans[i][j] = 0 if entry[j] == j - i else 1
dp = [[float("inf")] * n for _ in range(n + 1)]
for i in range(1, n + 1):
for j in range(i - 1, n):
if j == 0:
dp[i][j] = 0 if entry[j] == 0 else 1
continue
# Case 1
if dp[i][j - 1] != float("inf"):
dp[i][j] = dp[i][j - 1] + 1
# Case 2
if entry[j] and dp[i - 1][j - 1] != float("inf"):
dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + 1)
# Case 3
if j - entry[j] - 1 >= 0 and dp[i - 1][j - entry[j] - 1] != float("inf"):
dp[i][j] = min(
dp[i][j], dp[i - 1][j - entry[j] - 1] + range_ans[j - entry[j]][j]
)
if j - entry[j] == 0 and i == 1:
dp[i][j] = min(dp[i][j], range_ans[j - entry[j]][j])
with open("taming.out", "w") as out:
for i in range(1, n + 1):
out.write(f"{dp[i][n - 1]}\n")