Substring
Explicación
Definamos como la frecuencia máxima del carácter para el nodo . Luego, ordenamos los nodos topológicamente para hacer programación dinámica sobre el DAG. Nuestra transición es simple:
mientras también incrementamos para el nodo actual donde representa , ya que podemos recoger una más de esta letra en nuestro camino.
Implementación
Complejidad temporal:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
string a;
cin >> a;
vector<vector<int>> adj(n);
vector<int> in_degree(n);
for (int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
a--;
b--;
in_degree[b]++;
adj[a].push_back(b);
}
queue<int> queue;
// dp[i][j] is the frequency of letter j when we are at node i.
vector<vector<int>> dp(n, vector<int>(26));
for (int i = 0; i < n; i++) {
if (in_degree[i] == 0) {
queue.push(i);
dp[i][a[i] - 'a']++;
}
}
// Run topological sort.
int size = 0;
while (size < n && queue.size() > 0) {
int cur = queue.front();
queue.pop();
for (int next : adj[cur]) {
for (int j = 0; j < 26; j++) {
// Update the frequency with the next occurrence.
if (j == (a[next] - 'a')) {
dp[next][j] = max(dp[cur][j] + 1, dp[next][j]);
} else {
dp[next][j] = max(dp[cur][j], dp[next][j]);
}
}
// Add the next node to the queue.
if (--in_degree[next] == 0) { queue.push(next); }
}
size++;
}
// No answer.
if (size < n) {
cout << -1 << endl;
return 0;
}
// Find the maximum frequency across all nodes and letters.
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < 26; j++) { ans = max(ans, dp[i][j]); }
}
cout << ans << endl;
}import java.io.*;
import java.util.*;
public class Substring {
// CodeSnip{Kattio}
public static void main(String[] args) throws IOException {
Kattio io = new Kattio();
int N = io.nextInt();
int M = io.nextInt();
char[] A = io.next().toCharArray();
ArrayList<Integer>[] adj = new ArrayList[N];
for (int i = 0; i < N; i++) { adj[i] = new ArrayList<>(); }
int inDegree[] = new int[N];
for (int i = 0; i < M; i++) {
int a = io.nextInt() - 1;
int b = io.nextInt() - 1;
inDegree[b]++;
adj[a].add(b);
}
Queue<Integer> queue = new LinkedList<>();
// dp[i][j] is the frequency of letter j when we are at node i
int dp[][] = new int[N][26];
for (int i = 0; i < N; i++) {
if (inDegree[i] == 0) {
// enqueue the node
queue.add(i);
dp[i][A[i] - 'a']++;
}
}
// topological sort
int size = 0;
while (size < N && queue.size() > 0) {
int cur = queue.poll();
for (int next : adj[cur]) {
for (int j = 0; j < 26; j++) {
// update the frequency with the next occurrence
if (j == (A[next] - 'a')) {
dp[next][j] = Math.max(dp[cur][j] + 1, dp[next][j]);
} else {
dp[next][j] = Math.max(dp[cur][j], dp[next][j]);
}
}
// add the next node to the queue
if (--inDegree[next] == 0) { queue.add(next); }
}
size++;
}
// no answer
if (size < N) {
System.out.println(-1);
return;
}
// find the maximum frequency across all nodes and letters
int ans = 0;
for (int i = 0; i < dp.length; i++) {
for (int j = 0; j < dp[i].length; j++) { ans = Math.max(dp[i][j], ans); }
}
System.out.println(ans);
}
}from collections import deque
n, m = map(int, input().split())
a = input()
adj = [[] for _ in range(n)]
in_degree = [0] * n
for _ in range(m):
x, y = map(int, input().split())
x -= 1
y -= 1
in_degree[y] += 1
adj[x].append(y)
queue = deque()
# dp[i][j] is the frequency of letter j when we are at node i.
dp = [[0] * 26 for _ in range(n)]
for i in range(n):
if in_degree[i] == 0:
queue.append(i)
dp[i][ord(a[i]) - ord("a")] += 1
# Run topological sort.
size = 0
while size < n and len(queue) > 0:
cur = queue.popleft()
for nxt in adj[cur]:
for j in range(26):
# Update the frequency with the next occurrence.
if j == ord(a[nxt]) - ord("a"):
dp[nxt][j] = max(dp[cur][j] + 1, dp[nxt][j])
else:
dp[nxt][j] = max(dp[cur][j], dp[nxt][j])
# Add the next node to the queue.
in_degree[nxt] -= 1
if in_degree[nxt] == 0:
queue.append(nxt)
size += 1
# No answer.
if size < n:
print(-1)
else: # Find the maximum frequency across all nodes and letters.
ans = 0
for i in range(n):
for j in range(26):
ans = max(ans, dp[i][j])
print(ans)