Tenzing and Balls
Explicación
Podemos empezar notando que todos los rangos que se eliminan deben ser disjuntos. Si dos rangos se solapan, se pueden combinar en un solo segmento. Si un segmento está dentro de otro, entonces el segmento más grande puede reemplazar al más pequeño.
Usando esta idea, el objetivo se puede pensar como el número mínimo de bolas restantes. Definimos como el número mínimo de bolas que quedan después de mirar las primeras bolas.
En la bola , tenemos dos opciones:
- No usarla en ningún segmento, así
- Emparejarla con una bola anterior del mismo color en la posición y eliminar todas las bolas de a , así
La fórmula se puede condensar aún más en
donde guarda el valor mínimo de sobre todas las posiciones anteriores tales que .
Después de hallar , actualizamos .
La respuesta final es .
Implementación
Complejidad temporal:
#include <bits/stdc++.h>
using namespace std;
const int INF = 1e9;
int main() {
int test_num;
cin >> test_num;
for (int t = 0; t < test_num; t++) {
int n;
cin >> n;
vector<int> balls(n);
for (int i = 0; i < n; i++) { cin >> balls[i]; }
vector<int> dp(n + 1, INF);
dp[0] = 0;
vector<int> best(n + 1, INF);
for (int i = 1; i <= n; i++) {
// keep or delete segment ending at index i
dp[i] = min(dp[i - 1] + 1, best[balls[i - 1]]);
// update best for this color with dp[i-1]
best[balls[i - 1]] = min(best[balls[i - 1]], dp[i - 1]);
}
cout << n - dp[n] << '\n';
}
}INF = 10**20
T = int(input())
for _ in range(T):
N = int(input())
balls = list(map(int, input().split()))
dp = [INF] * (N + 1)
dp[0] = 0
best = [INF] * (N + 1)
for i in range(1, N + 1):
# keep or delete segment ending at index i
dp[i] = min(dp[i - 1] + 1, best[balls[i - 1]])
# update best for this color with dp[i-1]
best[balls[i - 1]] = min(best[balls[i - 1]], dp[i - 1])
print(N - dp[N])