Anda di halaman 1dari 77

ndice general

1. Ad-hoc
1.1. Invertir Bytes
1.2. Ao bisiesto .
1.3. Doomsday . .
1.4. Hanoi . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

3
3
3
3
3

2. Estructuras
2.1. Union - Find . . . . . . . . . . . . .
2.2. BIT . . . . . . . . . . . . . . . . .
2.3. Segment Tree . . . . . . . . . . . .
2.4. Segment Tree con Lazy Propagatin
2.5. Trie . . . . . . . . . . . . . . . . .
2.6. Arbol Binario de Busqueda . . . . .

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

4
4
5
5
7
8
10

3. Complete Search
3.1. El problema de las ocho reinas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2. El problema de las ocho reinas acelerado con Bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

12
12
13

4. Divide y venceras
4.1. Busqueda Binaria (Recursivo)
4.2. Busqueda Binaria (Iterativo) .
4.3. MergeSort . . . . . . . . . . .
4.4. Meet in the Middle . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

14
14
14
15
16

5. Programacin Dinamica
5.1. El problema de la mochila y Subset Sum . . . . .
5.2. El problema de la mochila(iterativo) . . . . . . .
5.3. Cambio de modenas . . . . . . . . . . . . . . . .
5.4. LIS (O(n2 )) . . . . . . . . . . . . . . . . . . . .
5.5. LIS (O(n log(n)) . . . . . . . . . . . . . . . . .
5.6. Suma maxima en rango . . . . . . . . . . . . . .
5.7. Suma maxima en rango 2D O(n4 ) . . . . . . . .
5.8. Suma maxima en rango 2D O(n3 ) . . . . . . . .
5.9. Maxima submatriz de ceros . . . . . . . . . . . .
5.10. Submatriz de suma maxima . . . . . . . . . . . .
5.11. Distancia de edicin (Algoritmo de Levenshtein)
5.12. Distancia de edicin (Recursivo) . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

18
18
19
20
21
21
22
22
23
23
24
25
26

6. Grafos
6.1. BFS . . . . . . . . . . . . . . . . . . . . . . .
6.2. DFS . . . . . . . . . . . . . . . . . . . . . . .
6.3. Topological Sort . . . . . . . . . . . . . . . . .
6.4. Dijkstra . . . . . . . . . . . . . . . . . . . . .
6.5. BellmandFord . . . . . . . . . . . . . . . . . .
6.6. Floyd Warshall . . . . . . . . . . . . . . . . .
6.7. Componentes Fuertemente Conexas . . . . . .
6.8. Componentes Fuertemente Conexas (Kosaraju)

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

27
27
27
28
28
29
30
31
32

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.
.
.
.
.

NDICE GENERAL

6.9. Componentes Fuertemente Conexas (Tarjan O(n + v) )


6.10. Minimum Spanning Tree (Kruskall) . . . . . . . . . .
6.11. Second Minimum Spanning Tree . . . . . . . . . . . .
6.12. Minimum Cut . . . . . . . . . . . . . . . . . . . . . .
6.13. MaxFlow . . . . . . . . . . . . . . . . . . . . . . . .
6.14. Lowest common ancestor (LCA) . . . . . . . . . . . .
6.15. Maximo Emparejamiento Bipartito . . . . . . . . . .
6.16. Puentes . . . . . . . . . . . . . . . . . . . . . . . . .
6.17. Puntos de Articulacin . . . . . . . . . . . . . . . . .
6.18. Camino Euleriano . . . . . . . . . . . . . . . . . . . .
6.19. Dijkstra Fast . . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

33
35
36
38
39
40
41
43
44
45
46

7. Matemticas
7.1. GCD . . . . . . . . . . . . . . . . . . . . . . .
7.2. LCM . . . . . . . . . . . . . . . . . . . . . . .
7.3. Algoritmo extendido de euclides . . . . . . . .
7.4. Exponenciacin rapida . . . . . . . . . . . . .
7.5. Criba de Erathostenes . . . . . . . . . . . . . .
7.6. Criba de Erathostenes Aumentada . . . . . . .
7.7. Triangulo de Pascal . . . . . . . . . . . . . . .
7.8. Combinaciones(Para numeros muy grandes) . .
7.9. Polinomios . . . . . . . . . . . . . . . . . . .
7.10. Fibonacci ( O(log(n)) ) . . . . . . . . . . . . .
7.11. Multiplicacin entero por cadena . . . . . . . .
7.12. Multiplicacin de numeros grandes (Karatsuba)
7.13. Integracion de Simpson . . . . . . . . . . . . .
7.14. Inverso modular . . . . . . . . . . . . . . . . .
7.15. El juego de Nim . . . . . . . . . . . . . . . . .
7.16. Fraccion . . . . . . . . . . . . . . . . . . . . .
7.17. Matriz . . . . . . . . . . . . . . . . . . . . . .
7.18. Gauss Jordan . . . . . . . . . . . . . . . . . .
7.19. Numeros romanos . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

47
47
47
47
48
48
49
49
49
50
51
51
52
52
53
53
53
55
56
59

8. Cadenas
8.1. Utilidades . . . . . . . . . . . . . . .
8.2. Boyer Moore . . . . . . . . . . . . .
8.3. Knuth Morris Pratt . . . . . . . . . .
8.4. Iesima permutacin . . . . . . . . . .
8.5. Algoritmo de Manacher . . . . . . . .
8.6. Longest Common Subsequence (LCS)
8.7. Suffix Array . . . . . . . . . . . . . .
8.8. Suffix Array DC3 . . . . . . . . . . .
8.9. Minima Rotacion Lexicografica . . .
8.10. Trie . . . . . . . . . . . . . . . . . .
8.11. Aplicaciones . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

60
60
60
61
62
62
64
64
67
68
69
71

9. Geometria Computacional
9.1. Interseccin de rectangulos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.2. Distancia Punto - Segmento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.3. Distancia Punto - Recta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

73
73
73
74

10. Utilitarios
10.1. Plantilla . . . . . . . . . . . . . . . . . . . .
10.2. Lectura rapida . . . . . . . . . . . . . . . . .
10.3. Espicificadores de formato para printf y scanf
10.4. Contar bits en 1 en un numero . . . . . . . .
10.5. Busqueda binaria . . . . . . . . . . . . . . .

75
75
76
76
76
77

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

Captulo 1

Ad-hoc
1.1.
1
2
3
4
5
6
7
8

// Entrada: Un entero sin signo de 32 bits


// Salida : El mismo numero pero con los bytes invertidos como si fuera una
cadena
int reverse_bytes(unsigned int i) {
return ((i >> 24) ) |
((i >> 8) & 0xFF00) |
((i << 8) & 0xFF0000) |
((i << 24));
}

1.2.
1
2
3

Doomsday

//Entrada: Una fecha (ene = 1, ..., dic = 12) Salida: Dia de la semana
string vec[7] = {"DOM","LUN","MAR","MIE","JUE","VIE","SAB"};
string doomsday(int dia, int mes, int anio){
int a, y, m, d;
a = (14 - mes) / 12;
y = anio - a;
m = mes + 12 * a - 2;
d = (dia + y + y/4 - y/100 + y/400 + (31*m)/12) % 7;
return vec[d];
}

1.4.
1
2
3
4

Ao bisiesto

bool esBisiesto(int y){


return ( ((y %4)==0 && (y %100)!=0) || (y %400)==0 );
}

1.3.
1
2
3
4
5
6
7
8
9
10

Invertir Bytes

Hanoi

int hanoi(int n){


if(n==1) return 1;
else return 2 * hanoi(n-1) + 1;
}

Captulo 2

Estructuras
2.1.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

Union - Find

struct UnionFind{
int p[MAX], r[MAX], setSize[MAX];
int n, numSets;
UnionFind(int _N){
reset(_N);
}
void reset(int N){
n = N;
numSets = n;
for(int i = 0; i <= n; i++){
p[i] = i;
r[i] = 0;
setSize[i] = 1;
}
}
int Find(int i){return (p[i] == i)?i:(p[i] = Find(p[i]));}
bool sameComponent(int i, int j){return Find(i) == Find(j);}
void Union(int i, int j){
if(!sameComponent(i, j)){
numSets--;
int x = Find(i), y = Find(j);
if(r[x] > r[y]){
p[y] = x;
setSize[x] += setSize[y];
} else
{
p[x] = y;
setSize[y] += setSize[x];
if (r[x] == r[y]) r[y]++;
}
}
}
int numDisjointSets(){
return numSets;
}
int sizeOfSet(int i){
return setSize[Find(i)];
}
};

CAPTULO 2. ESTRUCTURAS

2.2.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

#include <iostream>
#include <cstring>
using namespace std;
#define MAXN 1000000
int
int
int
int

T[MAXN + 1];
A[MAXN];
N;
lowbit(int i) {
return (i & -i);

}
int sum(int i){
int value = 0;
for(; i > 0; i-= lowbit(i))
value+= T[i];
return value;
}
int sum(int i, int j){
return i > 1 ? sum(j) - sum(i-1) : sum(j);
}
void update(int i, int value){
for(; i <= N ; i += lowbit(i))
T[i] += value;
}
void build(){
memset(T, 0, sizeof(T));
for(int i=0; i < N; i++)
update(i+1, A[i]);
}
int main(){
cin >> N;
for(int i = 0; i < N; ++i)
cin >> A[i];
build();
cout << sum( 1, N ) << endl;
return 0;
}

2.3.
1
2
3
4
5
6
7
8
9
10
11

BIT

Segment Tree

#include <ctime>
#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
int c[100000];
int tree[400001];
//si es segment tree de -,* o / solo sustituir el + en init query y update
void init(int node,int a,int b)
{
if(a==b)

CAPTULO 2. ESTRUCTURAS
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

{
tree[node]=c[a];
return ;
}
init(2*node+1,a,(a+b)/2);
init(2*node+2,(a+b)/2+1,b);
tree[node]=tree[2*node+1]+tree[2*node+2];
}
// consula para llamar query(0,0,n-1,desde,hasta)
int query(int node,int a,int b,int p,int q)
{
//la consulta se hace en el rango desde p a q, a y b son los limites del
rango
if( q<a || b<p )return 0;
if(p<=a && b<=q)
{
return tree[node];
}
return query(2*node+1,a,(a+b)/2,p,q)+query(2*node+2,(a+b)/2+1,b,p,q);
}
//sustituir para llamar(0,0,n-1,posicion,valor)
void update(int node,int a,int b,int p,int val)
{
if(p<a || b<p)return;
if(a==b)
{
tree[node]=val;
return ;
}
update(2*node+1,a,(a+b)/2,p,val);
update(2*node+2,(a+b)/2+1,b,p,val);
tree[node]=tree[2*node+1]+tree[2*node+2];
}
int main()
{
int n,aux;
for(int i=0; i<n; i++)
{
scanf(" %d",&aux);
c[i]=aux;
}
init(0,0,n-1);
//ejemplo de sustitucion tree[a]=val
int a,b;
int val;
scanf(" %d %d",&a,&val);
a--;//solo si los subindices del problema van de 1...n
update(0,0,n-1,a,val);
//ejemplo de consulta x=SUM(a,a+1,....,b)
scanf(" %d %d",&a,&b);
a--;//solo si los subindices del problema van de 1...n
b--;//solo si los subindices del problema van de 1...n
int x=query(0,0,n-1,a,b);
printf(" %d\n",x);
printf("\n");
return 0;
}

CAPTULO 2. ESTRUCTURAS

Otra implementacion en java:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

public class SegmentTree{


static final int NEUT = 2147483647;// Cambiar segun operacion
public static void main(String[] args){
int[] m = {4,0,7,1,3,5,8,8,3,2,2,1};
int[] rmq = new int[m.length*4];
rmq_init(1, 0, m.length, rmq, m);
System.out.println(rmq_query(1, 0, m.length, rmq, 2, 5));
}
public static int LEFT(int n){ return 2*n; }
public static int RIGHT(int n){ return 2*n+1; }
public static int oper(int a, int b){ return Math.min(a, b); }
public static void rmq_init(int n, int s, int e, int[] rmq, int[] m){
if(s+1 == e)
rmq[n] = m[s];
else{
rmq_init(LEFT(n), s, (s+e)/2, rmq, m);
rmq_init(RIGHT(n), (s+e)/2, e, rmq, m);
rmq[n] = oper(rmq[LEFT(n)], rmq[RIGHT(n)]);
}
}
public static void rmq_update(int n, int s, int e, int[] rmq, int[] m, int p
, int v){
if(s+1 == e)
rmq[n] = m[s] = v;
else{
if(p < (s+e)/2)
rmq_update(LEFT(n), s, (s+2)/2, rmq, m, p, v);
else
rmq_update(RIGHT(n), (s+e)/2, e, rmq, m , p, v);
rmq[n] = oper(rmq[LEFT(n)], rmq[RIGHT(n)]);
}
}
public static int rmq_query(int n, int s, int e, int[] rmq, int a, int b){
if(a >= e || b <= s)
return NEUT;
else if (s >= a && e <= b)
return rmq[n];
else{
int l = rmq_query(LEFT(n), s, (s+e)/2, rmq, a, b);
int r = rmq_query(RIGHT(n), (s+e)/2, e, rmq, a, b);
return oper(l, r);
}
}
}

2.4.
1
2
3
4
5

Segment Tree con Lazy Propagatin

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

CAPTULO 2. ESTRUCTURAS
6
7
8
9
10
11
12

struct Node{
long long sum; //suma de hijos
long long offset;//suma que no propaga de total nodo
}Tree[500000];

void Update(long long node,long long lo,long long hi,long long i,long long j,
long long val){
13
if(lo>j || hi<i)
14
return;
15
16
17
18
19
20
21
22
23
24
25
26
27

if(lo>=i && hi<=j){


Tree[node].sum+=(hi-lo+1)*val;
Tree[node].offset+=val;
}else{
long long mid=(lo+hi)>>1;
Update(2*node,lo,mid,i,j,val);
Update(2*node+1,mid+1,hi,i,j,val);
Tree[node].sum=Tree[2*node].sum+Tree[2*node+1].sum+(hi-lo+1)*Tree[node].
offset;
}
}

long long Query(long long node,long long lo,long long hi,long long i,long long j
,long long offst){
28
if(lo>j || hi<i)
29
return 0;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

if(lo>=i && hi<=j){


return offst*(hi-lo+1)+Tree[node].sum;
}else{
long long mid=(lo+hi)>>1;
offst+=Tree[node].offset;
long long q1=Query(2*node,lo,mid,i,j,offst);
long long q2=Query(2*node+1,mid+1,hi,i,j,offst);
return q1+q2;
}
}
void Clear(long long N){
for(long long i=0;i<4*N;i++){
Tree[i].offset=Tree[i].sum=0;
}
}
int main(){
int N,ofst=0;
Clear(N);
cout<<Query(1,1,N,x,y,ofst)<<endl;
Update(1,1,N,x,y,val);
return 0;
}

2.5.
1
2
3

Trie

#include <iostream>
#include <vector>
#include <algorithm>

CAPTULO 2. ESTRUCTURAS
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

#include <cstdio>
#include <fstream>
using namespace std;
struct Trie{
Trie* hijos[26];
bool esfin;
vector<int> idhijos;
Trie(){
esfin = false;
for(int i = 0; i < 26; ++i)
hijos[i] = NULL;
}
};
void insertar(Trie* v, char* c){
if(c[0] == \0)
v->esfin = true;
else{
int k = c[0] - a;
if(v->hijos[k] == NULL){
v->hijos[k] = new Trie();
(v->idhijos).push_back(k);
}
insertar(v->hijos[k], c+1);
}
}
void ordenarids(Trie *t){
sort((t->idhijos).begin(), (t->idhijos).end());
int tam = (t->idhijos).size();
for(int i = 0; i < tam; i++){
int k = t->idhijos[i];
ordenarids(t->hijos[k]);
}
}
bool haysol = false;
int tmp, caso;
char vacio[25]="";
string cad;
void mostrar(Trie* v, string p, char* pr){
if(pr[0] == \0){
if(v->esfin){
haysol = true;
puts(p.c_str());
}
int tam = (v->idhijos).size();
for(int i = 0; i < tam; ++i){
int k = v->idhijos[i];
mostrar(v->hijos[k], p + ((char)(a+k)), vacio);
}
}
else{
int k = pr[0] - a;
if(v->hijos[k] != NULL){
bool aux = (v->hijos[k])->esfin;
(v->hijos[k])->esfin = false;
mostrar(v->hijos[k], p, pr+1);

CAPTULO 2. ESTRUCTURAS
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

(v->hijos[k])->esfin = aux;
}
}
}
int main(){
//freopen("entrada.in","r",stdin);
Trie* t;
t = new Trie();
scanf(" %d", &tmp);
char cadena[25];
while(tmp--){
scanf(" %s", cadena);
insertar(t, cadena);
}
ordenarids(t);;
cin >> tmp;
for(caso = 1; caso <= tmp; caso++){
scanf(" %s", cadena);
cad = cadena;
haysol = false;
printf("Case # %d:\n", caso);
mostrar(t, cad, cadena);
if(!haysol)
puts("No match.");
}
return 0;
}

2.6.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

Arbol Binario de Busqueda

struct nodo{
int valor;
nodo* izq;
nodo* der;
nodo(){
valor = (1<<30);
izq = NULL;
der = NULL;
}
nodo(int _v){
valor = _v;
izq = NULL;
der = NULL;
}
};
void insertar(int val, nodo **n){
if((*n) == NULL)
*n = new nodo(val);
else
if(val > (*n)->valor)
insertar(val, &((*n)->der));
else
insertar(val, &((*n)->izq));

10

CAPTULO 2. ESTRUCTURAS
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

}
void inorden(nodo *n){
if(n != NULL){
inorden(n->izq);
cout << (n->valor) <<" ";
inorden(n->der);
}
}
int main(){
nodo *raiz;
raiz = NULL;
int nro,tmp;
cin >> nro;
while(nro--){
cin >> tmp;
insertar(tmp, &raiz);
}
cout << "IN-ORDEN" << endl;
inorden(raiz);
return 0;
}

11

Captulo 3

Complete Search
3.1.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

El problema de las ocho reinas

int nrosol, f, c;
int sol[10];
bool sePuede(int fila, int col){
if(col != c &&fila == f)return false;
for(int i = col - 1 ; i >= 1; i--)
if(sol[i] == fila || (abs(sol[i] - fila) == abs(i - col)))
return false;
return true;
}
void solve(int col){
if(col == 9){
if(sol[c] == f){
printf(" %2d
%d", nrosol++, sol[1]);
for(int i = 2; i <= 8; i++)
printf(" %d", sol[i]);
printf("\n");
}
return ;
}
for(int i = 1; i <= 8; i++)
if(sePuede(i, col)){
sol[col] = i;
solve(col + 1);
}
}
int main(){
int T; cin >> T;
while(T--){
printf( "SOLN
COLUMN\n #
1 2 3 4 5 6 7 8\n\n" );
cin >> f >> c;
scanf(" %d %d", &f, &c);
nrosol = 1;
memset(sol, 0, sizeof(sol));
sol[c] = f;
solve(1);
}
return 0;
}

12

CAPTULO 3. COMPLETE SEARCH

3.2.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

El problema de las ocho reinas acelerado con Bits

class Solution {
public:
int ans, lim;
void solve(int row, int ld, int rd) {
if (row == lim) { // have placed row queens
ans ++; // we have a solution
return;
}
int pos = lim & (~(row | ld | rd)); // valid positions
while (pos != 0) {
int p = pos & (-pos); // rightmost position
pos -= p; // have tried this
solve(row + p, (ld + p) << 1, (rd + p) >> 1);
}
}
int totalNQueens(int n) {
ans = 0;
lim = (1 << n) - 1;
solve(0, 0, 0);
return ans;
}
};

13

Captulo 4

Divide y venceras
4.1.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

template <class T>


int binsearch(const T array[], int len, T what)
{
if (len == 0) return -1;
int mid = len / 2;
if (array[mid] == what) return mid;
if (array[mid] < what) {
int result = binsearch(array+mid+1, len-(mid+1), what);
if (result == -1) return -1;
else return result + mid+1;
}
if (array[mid] > what)
return binsearch(array, mid, what);
}
#include <iostream>
int main()
{
int array[] = {2, 3, 5, 6, 8};
int result1 = binsearch(array, sizeof(array)/sizeof(int), 4),
result2 = binsearch(array, sizeof(array)/sizeof(int), 8);
if (result1 == -1) std::cout << "4 not found!" << std::endl;
else std::cout << "4 found at " << result1 << std::endl;
if (result2 == -1) std::cout << "8 not found!" << std::endl;
else std::cout << "8 found at " << result2 << std::endl;
return 0;
}

4.2.
1
2
3
4
5

Busqueda Binaria (Recursivo)

Busqueda Binaria (Iterativo)

template <class T>


int binSearch(const T arr[], int len, T what) {
int low = 0;
int high = len - 1;
while (low <= high) {
14

CAPTULO 4. DIVIDE Y VENCERAS


6
7
8
9
10
11
12
13
14
15
16

int mid = (low + high) / 2;


if (arr[mid] > what)
high = mid - 1;
else if (arr[mid] < what)
low = mid + 1;
else
return mid;
}
return -1; //indica que no esta
}

4.3.

MergeSort

Primera implementacion:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

//Entrada: p = indice del primer elemento a ordenar


//
r = indice del ultimo elemento a ordenar
//Salida: El vector "a" ordenado
int a[LIM], L[LIM/2 + 4], R[LIM/2 + 4];
void fusionar(long p,long q,long r) {
long i,j,k,ind1,ind2;
ind1 = ind2 = 1;
for(i = p; i <= q; i++)
L[ind1++] = a[i];
L[ind1] = inf;
for(i = q+1; i <= r; i++)
R[ind2++] = a[i];
R[ind2] = inf;
i = j = 1;
for(k = p; k <= r; k++)
if(L[i] > R[j]) {
a[k] = R[j];
j++;
} else {
a[k] = L[i];
i++;
}
}
void mergeSort(long p,long r) {
if(p < r) {
long q = (p+r)/2;
mergeSort(p,q);
mergeSort(q+1,r);
fusionar(p,q,r);
}
}
Segunda implementacin:

1
2
3
4
5
6
7
8

//Entrada: Un array
//Salida: El vector "array" ordenado
//
La cantidad optima de intercambios
int array[MAXN];
int temp[MAXN];
int intercambios = 0;
int d = 0;
void mergesort(int inicio, int length) {

15

CAPTULO 4. DIVIDE Y VENCERAS


9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

16

if(length<=1)
return;
mergesort(inicio, length/2);
mergesort(inicio+length/2, length-length/2);
int i = inicio;
int j = inicio+length/2;
int n = 0;
while(i<inicio+length/2 && j<inicio+length)
if(array[i]<array[j]) {
temp[n++] = array[i++];
intercambios+=d; //para contar los intercambios
} else {
temp[n++] = array[j++];
d++;
}
while(i<inicio+length/2) {
temp[n++] = array[i++];
intercambios+=d;
}
while(j<inicio+length)
temp[n++] = array[j++];
memcpy(array+inicio, temp, length*sizeof(int));
}

4.4.

Meet in the Middle

Si generamos los subconjuntos de una lista de N elementos; sabemos que existen 2N subconjuntos, pero esta complejidad es demasiado cuando N es grande, digamos (N>20).
Problema.- Dado una secuencia de N (1<= N <=34) nmeros, determinar cuntos subconjuntos de esta secuencia tiene
una suma entre A y B.
Esta tcnica consiste en dividir en dos listas por la mitad, Luego generamos las sumatorias de los subconjuntos de
cada lista y los ordenamos. Luego combinar ambos resultados.
Considerare la sumatoria de conjunto vacio como 0.
Ejemplo:
L= { 2 , 5 , 6 , 1, 9};
A=5, B=15
Los dividimos en los listas por la mitad.
X= { 2 , 5, 6}
Y= { 1 , 9}
Generamos los subconjuntos de cada lista.
X = { 0, 2, 5 , {2,5}, 6,{2,6}, {5,6} ,{2,5,6} }
Y= { 0, 1, 9, {1,9} }
Sumatorias de cada subconjunto de manera ordenada.
X= {0,2,5,6,7,8,11,13}
Y= {0,1,9,10}
Combinar resultados
Tenemos que recorrer la lista X y ver cunto nos falta para llegar al intervalo [A, B].
Si el primer elemento de X tenemos 0 entonces en la lista Y tenemos que buscar cuantos elementos existen entre
5 y 15.
Si el segundo elemento de X tenemos 2 entonces en la lista Y buscamos cuantos existen entre 3 y 13.

CAPTULO 4. DIVIDE Y VENCERAS

17

x
Si bien se dan cuenta es muy importante tener ambas listas de una manera ordenada para poder buscar cuantos elementos existen en la segunda matriz entre ese intervalo.
El algoritmo sigue buscando hasta terminar con el ltimo elemento de la primera lista.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

#include <vector>
#include <algorithm>
#include <iostream>
#define all(v) (v).begin(),(v).end()
#define rall(v) (v).rbegin(),(v).rend()
#define sz size()
using namespace std;
vector<int>A,B;
void subsets(vector<int> v, vector<int>&ans){
ans.clear();
int n=v.sz;
for(int mask=0;mask<(1<<n);mask++){
int sum=0;
for(int j=0;j<v.sz;j++)if(mask&(1<<j))sum+=v[j];
ans.push_back(sum);
}
sort(all(ans));
}
int main(){
int N,X,Y,n,nx;
cin>>N>>X>>Y;
vector<int>v(N);
for(int i=0;i<N;i++)cin>>v[i];
n=N/2;
subsets(vector<int>(v.begin(),v.begin()+n),A);
subsets(vector<int>(v.begin()+n,v.end()),B);
long long ans=0;
for(int i=0;i<A.sz;i++){
int val=A[i];
int frs=X-val;
int scd=Y-val;
int x1=lower_bound(all(B),frs)-B.begin();
int y1=upper_bound(all(B),scd)-B.begin();
if(y1>=x1)ans+=(y1-x1);
}
cout<<ans<<endl;
return 0;
}

Captulo 5

Programacin Dinamica
5.1.

El problema de la mochila y Subset Sum

Subset Sum:
(
OP T (j 1, W )
(wj > W )
OP T (j, W ) = max
wj + OP T (j 1, W wj ) (wj W )
0-1 Mochila
(
OP T (j 1, W )
OP T (j, W ) = max
vj + OP T (j 1, W wj )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

(wj > W )
(wj W )

/*
Nota:
Si los pesos son muy grandes o el valor de llenar la mochila es muy grande
se puede utilizar un map en vez de una matriz para la memoizacion
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
long long int lib;
bool sel[35][1005], sol[35];//para reconstruccion (*)
int cant ; // * cantidad de elementos tomados
long long int dp[35][1005], v[35], p[35];//dp[OBJETOS + 1][LIBRE
long long int mochila(int i, int libre) { // Llamar mochila(N-1,
if(i < 0)return 0LL;
long long int &ans = dp[i][libre];
if(ans != -1) return ans;
ans = mochila(i-1, libre);// no lo tomo
if(p[i] <= libre) { // si cabe en el espacio disponible
ans = max(ans ,v[i] + mochila(i-1, libre - p[i])); // pruebo
if(ans == v[i] + mochila(i-1, libre - p[i]))//si se tomo el
sel[i][libre] = true;// marco como tomado (*)
}
return ans;
}

+ 1]
libre)

si lo tomaria
objeto (*)

//* Marca en el vector sol[ELEMEMTOS] los elementos que fueron tomados


void reconstruir(int i, int libre) {
18

CAPTULO 5. PROGRAMACIN DINAMICA


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

if(i < 0) return;


if(sel[i][libre]) { //si fue seleccionado
sol[i] = true;//marco
cant++;
reconstruir(i-1, libre - p[i]);
} else
reconstruir(i-1, libre);
}
int main() {
int n;
scanf(" %d %lld", &n, &lib);
for(int i = 0; i < n; i++)
scanf(" %lld %lld", &p[i], &v[i]);
memset(dp, -1, sizeof(dp));
memset(sel, false, sizeof(sel));//para la reconstruccion (*)
printf(" %lld\n", mochila(n-1, lib));
// imprimir los elementos
memset(sol, false, sizeof(sol));
cant = 0;
reconstruir(n-1, lib);
printf(" %d\n", cant);
for(int i = 0; i < n; i++)
if(sol[i])
printf(" %lld %lld\n", p[i], v[i]);
return 0;
}

5.2.
1
2
3
4
5
6
7
8

El problema de la mochila(iterativo)

/*
Nota:
-Tomar en cuenta que para calcular la fila i solo se necesita la fila i-1
entonces,
si el problema utiliza demasiada memoria o no entra se puede hacer el mismo
procedimiento
con solo 2 vectores llenando la fila actual con la fila ya calculada
y luego actual.swap(anterior), para todas la filas

- La version recursiva corre mas rapido por que no es necesario llenar toda la
matriz dp
9 */
10 #include <cstdio>
11 #include <algorithm>
12 #include <cstring>
13
14
15
16
17
18
19
20
21
22
23
24

using namespace std;


long long int d[35], w, lib;
//Para recosntruccion (*)
bool sel[35][1005]; //seleccionados (*)
bool sol[35];//el elemento fue seleccionado (*)
int cant ; // * cantidad de elementos tomados (*)
long long int dp[35][1005], v[35], p[35];//dp[OBJETOS + 1][LIBRE + 1]
long long int mochila(int n, int libre) { //Llamar con mochila(N, libre)

19

CAPTULO 5. PROGRAMACIN DINAMICA

memset(sel, false, sizeof(sel));


memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++)
for(int j = 1; j<= libre; j++)
if(p[i-1] <= j) {
dp[i][j] = max(dp[i-1][j-p[i-1]] + v[i-1], dp[i-1][j]);
if(dp[i][j] == dp[i-1][j-p[i-1]] + v[i-1])// se selecciono el elemento ?
(*)
sel[i][j] = 1; // marcar (*)
} else
dp[i][j] = dp[i-1][j];

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

return dp[n][libre];
}
void reconstruir(int n, int libre) {
int j = libre;
cant = 0;
memset(sol, false, sizeof(sol));
for(int i = n; i >= 1; i--)
if(sel[i][j] == 1) {
sol[i-1] = true;
cant++;
j = j - p[i-1];
}
}
int main() {
int n;
scanf(" %d %lld", &n, &lib);//N objetos y LIV espacio de la mochila
for(int i = 0; i < n; i++)
scanf(" %lld %lld", &p[i], &v[i]);
memset(dp, -1, sizeof(dp));
memset(sel, false, sizeof(sel));//para reconstruccion (*)
printf(" %lld\n", mochila(n, lib));
reconstruir(n, lib);
printf(" %d\n", cant);
for(int i = 0; i < n; i++)
if(sol[i])
printf(" %lld %lld\n", p[i], v[i]);
return 0;
}

5.3.
1
2
3
4
5
6
7
8
9

20

Cambio de modenas

long long int dp[30001];


int money[]={1,5,10,25,50};
void coinchange(int sum){
memset(dp, 0, sizeof(a));
dp[0]=1;
for(int i=0;i<5;i++)
for(int j=money[i];j<=sum;j++)
dp[j]+=dp[j-money[i]];
}

CAPTULO 5. PROGRAMACIN DINAMICA

5.4.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
vector<long long int> v;
vector<long long int> ancho;
vector<long long int> dp;
int t, n;
long long int lis(int i) {
if(i == 0)return ancho[0];//(*) si no es pesado 1
long long int ans = dp[i];
if(ans != -1LL) return ans;
ans = ancho[i];//(*) 1
for(int j = 0; j < i; j++)
if(v[j] < v[i]) // si no es estrictamente creciente "<="
ans = max(ans, ancho[i] + lis(j)); // 1 + lis(j)
return dp[i] = ans;
}
int solve() {
(vector<long long int>(n, -1LL)).swap(dp);
long long int ans = 0;
for(int i = n-1; i >= 0; i--)
ans = max(ans, lis(i));
return ans;
}
int main() {
scanf(" %d", &n);
(vector<long long int>(n)).swap(v);
(vector<long long int>(n)).swap(ancho);
for(int i = 0; i < n; i++)
scanf(" %lld", &v[i]);
for(int i = 0; i < n; i++)//si es pesado
scanf(" %lld", &ancho[i]);//
printf("lis = %d\n", solve());
return 0;
}

5.5.
1
2
3
4
5
6
7
8
9
10
11

LIS (O(n2 ))

LIS (O(n log(n))

#include <algorithm>
#include <cstdio>
#include <stack>
using namespace std;
#define MAX_N 100000
void imprimir(int end, int a[], int p[]) {
int x = end;
stack<int> s;
for (; p[x] >= 0; x = p[x]) s.push(a[x]);

21

CAPTULO 5. PROGRAMACIN DINAMICA


12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

printf(" %d\n", a[x]);


for (; !s.empty(); s.pop()) printf(" %d\n", s.top());
}
int main() {
int A[MAX_N], L[MAX_N], L_id[MAX_N], P[MAX_N];
int n, tmp;
scanf(" %d", &n);
for(int i = 0; i < n; i++)
scanf(" %d", &A[i]);
int lis = 0, lis_end = 0;
for (int i = 0; i < n; i++) {
int pos = lower_bound(L, L + lis, A[i]) - L;
L[pos] = A[i];
L_id[pos] = i;//(*) marcamos que posicion es la que estamso guardando
P[i] = pos ? L_id[pos - 1] : -1;//(*) El padre del i esimo elemento
if (pos + 1 > lis) {
lis = pos + 1;
lis_end = i;
}
}
printf(" %d\n", lis);
imprimir(lis_end, A, P);
return 0;
}

5.6.
1
2
3
4
5
6
7
8
9
10
11
12

//Algoritmo de kadane
//Entrada: Un vector de numero enteros
//Salida : La suma maxima de alguno de rangos en O(n)
long long int maxrangesum(vector<int> &v) {
long long int sum = 0, ans = -(1LL<<60);//la maxima suma podria ser negativa
for(int i = 0; i < v.size(); i++) {
sum += v[i];
ans = max(ans, sum);
if(sum < 0) sum = 0;
}
return ans;
}

5.7.
1
2
3
4
5
6
7
8
9
10

Suma maxima en rango

Suma maxima en rango 2D O(n4 )

#include <cstdio>
#include <algorithm>
#define MAX 103
using namespace std;
int v[MAX][MAX] = {0};
int main() {
int n, tmp;
scanf(" %d", &n);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) {

22

CAPTULO 5. PROGRAMACIN DINAMICA


11
12
13
14
15
16
17
18
19
20

scanf(" %d", &v[i][j]);


v[i][j] += (v[i-1][j] + v[i][j-1] - v[i-1][j-1]);
}
int ans = -127*100*100;
for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++)
for(int k = i; k <= n; k++)for(int l = j; l <= n; l++)
ans = max(ans, v[k][l] - v[i-1][l] - v[k][j-1] + v[i-1][j-1]);
printf(" %d\n", ans);
return 0;
}

5.8.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

Suma maxima en rango 2D O(n3 )

#include <algorithm>
#include <cstdio>
using namespace std;
int n, A[101][101] = {0}, maxSubRect, subRect;
int main() { // O(n^3) 1D DP + greedy (Kadane) solucion
scanf(" %d", &n);
// La dimension de la matriz
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) {
scanf(" %d", &A[i][j]);
A[i][j] += A[i][j - 1]; // vamos acumulando de fila en fila
}
maxSubRect = -127*100*100; // El valor mas bajo para la respuesta
for (int l = 1; l <= n; l++)
for (int r = l; r <= n; r++) {
subRect = 0;
for (int row = 1; row <= n; row++) {
// Max 1D Range Sum en las columnas de la fila i
subRect += A[row][r] - A[row][l - 1];
// El algoritmo de Kadane en las filas
if (subRect < 0) subRect = 0;
// golosamente, reiniciamos si sum < 0
maxSubRect = max(maxSubRect, subRect);
}
}
printf(" %d\n", maxSubRect);
return 0;
}

5.9.
1
2
3
4
5
6
7
8

23

Maxima submatriz de ceros

#include <vector>
#include <iostream>
#include <stack>
using namespace std;
int main(){
int n, m;
cin >> n >> m;
vector < vector<char> > a (n, vector<char> (m));

CAPTULO 5. PROGRAMACIN DINAMICA


9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

for (int i=0; i<n; ++i)


for (int j=0; j<m; ++j)
cin >> a[i][j];
int ans = 0;
vector<int> d (m, -1);
vector<int> dl (m), dr (m);
stack<int> st;
for (int i=0; i<n; ++i) {
for (int j=0; j<m; ++j)
if (a[i][j] == 1)
d[j] = i;
while (!st.empty()) st.pop();
for (int j=0; j<m; ++j) {
while (!st.empty() && d[st.top()] <= d[j]) st.pop();
dl[j] = st.empty() ? -1 : st.top();
st.push (j);
}
while (!st.empty()) st.pop();
for (int j=m-1; j>=0; --j) {
while (!st.empty() && d[st.top()] <= d[j]) st.pop();
dr[j] = st.empty() ? m : st.top();
st.push (j);
}
for (int j=0; j<m; ++j)
ans = max (ans, (i - d[j]) * (dr[j] - dl[j] - 1));
}
cout << ans;
return 0;
}

5.10.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Submatriz de suma maxima

void subMatriz_con_sumaMaxima(int m[n][n]){


for(int i = 1; i <= n; i++){
vector<int> vc(n + 1,0);//para aplicar DP magico
for(int j = i; j <= n; j++){
mn_temp = n * n;
for(int k = 1; k <= n; k++)
vc[k] += m[j][k];
dp[0] = 0;
for(int i = 1; i <= n;i++){
dp[i] = max(vc[i], dp[i-1] + vc[i]);
if(res < dp[i])
res = dp[i];
}
}
}
printf(" %d\n",res);
}

24

CAPTULO 5. PROGRAMACIN DINAMICA

5.11.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

25

Distancia de edicin (Algoritmo de Levenshtein)


<string>
<vector>
<algorithm>
<iostream>

#include
#include
#include
#include

using namespace std;


/*Encuentra la distancia de edicion entre 2 cadenas*/
/*
El numero minimos de cambios para transformar la cadena s1 en la cadena s2, con
los siguientes cambios:
- Elimina una letra de una de las cadenas
- Inserta una letra en una de las cadenas
- Reemplaza una letra en una de las cadenas
*/
int levenshtein(const string &s1, const string &s2)
{
int N1 = s1.size();
int N2 = s2.size();
int i, j;
vector<int> T(N2+1);
for ( i = 0; i <= N2; i++
T[i] = i;

for ( i = 0; i < N1; i++ ) {


T[0] = i+1;
int corner = i;
for ( j = 0; j < N2; j++ ) {
int upper = T[j+1];
if ( s1[i] == s2[j] )
T[j+1] = corner;
else
T[j+1] = min(T[j], min(upper, corner)) + 1;
corner = upper;
}
}
return T[N2];
}
int main(){
int casos;
cin >> casos;
string a, b;
while(casos--){
cin >> a >> b;
if(a.size() > b.size())
swap(a,b);
cout << levenshtein(a,b) << endl;
}
return 0;
}

CAPTULO 5. PROGRAMACIN DINAMICA

5.12.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

Distancia de edicin (Recursivo)

#include <cstdio>
#include <cstring>
#define MAXS 2005
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
using namespace std;
char a[MAXS], b[MAXS];
int ta, tb;
int casos;
int dp[MAXS][MAXS];
int solve(int ta, int tb){
if(ta < 0 && tb < 0)
return 0;
if(ta < 0)
return tb + 1;
if(tb < 0)
return ta + 1;
int &ans = dp[ta][tb];
if(ans == -1){
ans = 1<<30;
if(a[ta] == b[tb] )
ans = min(ans, solve(ta - 1, tb - 1));
else
ans = min(ans, 1 + solve(ta - 1, tb - 1));// con un solo cambio
convierto en lo mismo
ans = min(ans, 1 + solve(ta - 1, tb
));
ans = min(ans, 1 + solve(ta
, tb - 1));
}
return ans;
}
int main(){
//freopen("entrada.in", "r", stdin);
scanf(" %d", &casos);
while(casos--){
scanf(" %s %s", a, b);
ta = strlen(a);
tb = strlen(b);
memset(dp, -1, sizeof(dp));
printf(" %d\n",solve(ta-1, tb - 1));
}
return 0;
}

26

Captulo 6

Grafos
6.1.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

#include <queue>
#include <vector>
#include <cstring>
#define MAXN 1000
using namespace std;
vector<int> grafo[MAXN];
int d[MAXN];
queue<int> cola;
void BFS(int ini){
memset(d,-1, sizeof d);
cola.push(ini);
d[ini] = 0;
while(!cola.empty()){
int act = cola.front();cola.pop();
for(int i = 0; i < grafo[act].size(); i++){
int ady = grafo[act][i];
if(d[ady] == -1){
d[ady] = d[act] + 1;
cola.push(ady);
}
}
}
}

6.2.
1
2
3
4
5
6
7
8
9

BFS

DFS

#define MAX 1001


#define pain 64
int n;
int mat[MAX][MAX];
bool visitado[MAX][MAX];
int di[]={1,1, 1,-1,-1,-1,0, 0};
int dj[]={1,0,-1, 1, 0,-1,1,-1};
void ff_dfs(int i, int j) {
27

CAPTULO 6. GRAFOS
10
11
12
13
14
15
16
17
18
19

28

visitado[i][j] = true;
for(int k=0; k<8; k++) {
int a = di[k] + i;
int b = dj[k] + j;
if(a >= 0 && b >= 0 && a < n && b < n &&!visitado[a][b]) {
if(mat[a][b]==pain) ff_dfs(a,b);
else visitado[a][b]=true;
}
}
}

6.3.

Topological Sort

Grafo Aciclico Dirigido (DAG)


Las tareas no son independientes y la ejecucin de una tarea slo es posible si otras tareas que ya se han ejecutado.
Solo hay un orden
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

using namespace std;


vector<int>graph[110];
bool visitado[110];
vector<int> sol;
int n,m;
void dfs(int node) {
visitado[node] = true;
for (int i = 0; i < graph[node].size(); i++) {
if (!visitado[graph[node][i]])
dfs(graph[node][i]);
}
sol.push_back(node);
}
void lim(){
for(int i=0;i<=110;i++)
graph[i].clear();
clr(visitado);
sol.clear();
}
int main() {
//llenado
for (int i = 1; i <= n; i++)
if(!visitado[i])dfs(i);
reverse(sol.begin(), sol.end());
//printsol
return 0;
}

6.4.
1
2
3
4
5
6
7

Dijkstra
for(int i = 0; i < nodos; ++i){
d[i] = INF;
v[i] = false;
}
d[ini] = 0;
q.insert(make_pair(0,ini));
while(!q.empty()){

CAPTULO 6. GRAFOS
act = (*(q.begin())).second;q.erase(q.begin());
if(v[act])continue;
v[act] = true;
for(int i = 0; i < grafo[act].size(); ++i){
ady = grafo[act][i].first;
peso = grafo[act][i].second;
if(!v[ady] && d[act] + peso < d[ady] ){
d[ady] = d[act] + peso;
q.insert(make_pair(d[ady],ady));
}
}

8
9
10
11
12
13
14
15
16
17
18
19
20
21

}
if(d[fin] != INF) cout << d[fin] << endl;
else cout << "unreachable" << endl;

6.5.

BellmandFord

Si un grafo contiene un ciclo de coste total negativo entonces este grafo no tiene solucin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#include
#include
#include
#include
#include

<cstdio>
<algorithm>
<cstring>
<vector>
<fstream>

#define MAX 205


#define oo 1LL<<59
using namespace std;
int n, m;
long long int t[MAX];

vector<pair<int,long long int> > g[MAX];


bool ciclo[MAX];
long long int d[MAX];
bool v[MAX];
void dfs(int i) {
v[i] = true;
d[i] = -1;//NO CALCULABLE
for(int j = 0; j < g[i].size(); j++)
if(!v[g[i][j].first])
dfs(g[i][j].first);
}
void bellmanford(int ini) {
//fill(d + 1, d + 1 + n, oo);
//---------------------------------------------------------for(int i = 1; i <= n; i++)d[i] = oo, ciclo[i] = false;
d[ini] = 0LL;
for(int i = 0; i < n-1; i++)
for(int u = 1; u <= n; u++)
if(d[u] != oo) // Nos aseguramos que ya existe un camino hasta u
for(int j = 0; j < g[u].size(); j++) {
pair<int,long long int> v = g[u][j];
d[v.first] = min(d[v.first], d[u] + v.second);//por que INF + (
pesonegativo) es menor que INF
37
}

29

CAPTULO 6. GRAFOS
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

//verificamos y marcamos todos los nodos que pertenecen a un ciclo negativo


for(int u = 1; u <= n; u++)
for(int j = 0; j < g[u].size(); j++) {
pair<int,int> v = g[u][j];
if(d[v.first] > d[u] + v.second)
ciclo[u] = ciclo[v.first] = true;//Ciclo negativo return -1
}
//--------------------------------------------------------//Todos los nodos accesibles desde un nodo con ciclo negativo tambien tienen
distancia NO CALCULABLE
memset(v, false, sizeof(v));
for(int i = 1; i <= n; i++)
if(ciclo[i] && !v[i])
dfs(i);
}
int main() {
freopen("in", "r", stdin);
int u, v, caso = 1;
while(scanf(" %d", &n) == 1) {
for(int i = 1; i <= n; i++) {
scanf(" %lld", &t[i]);
g[i].clear();
}
scanf(" %d", &m);
while(m--) {
scanf(" %d %d", &u, &v);
long long int tmp = t[v]-t[u];
g[u].push_back(make_pair(v, tmp * tmp * tmp));
}
bellmanford(1);
scanf(" %d", &m);//querys
printf("Set # %d\n", caso++);
while(m--) {
scanf(" %d", &v);
if(d[v] < 3 || d[v] == oo)//No accecible o tiene ciclo negativo
puts("?");
else
printf(" %lld\n", d[v]);//Distancia correcta
}
}
return 0;
}

6.6.
1
2
3
4
5
6
7
8

Floyd Warshall

int dp[100][100]; //grafo matriz de ady


void floyd_warshall(){
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dp[i][j] = min(dp[i][j],dp[i][k] + dp[k][j]);
}

30

CAPTULO 6. GRAFOS

6.7.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

Componentes Fuertemente Conexas

#include
#include
#include
#include
#include
#include
#include

<cstring>
<string>
<cstdio>
<cstdlib>
<vector>
<algorithm>
<iostream>

#define clr(a) memset(a,0,sizeof(a))


#define pb push_back
using namespace std;
/*
Finding Strongly Connected Components
*/
vector<int>grafo[N];
vector<int>gaux;
bool visitado[N];
void dfs(int u){
visitado[u]=true;
for(int i=0;i<grafo[u].size();i++){
if(!visitado[grafo[u][i]]) dfs(grafo[u][i]);
}
}
int main(){
//r(input);
int t;
int x,y;
int n,m;
sc(" %d",&t);
while(t--){
sc(" %d %d",&n,&m);
clr(visitado);
for(int i=0;i<=n;i++)
grafo[i].clear();
gaux.clear();
while(m--){
sc(" %d %d",&x,&y);
grafo[x].pb(y);
}
int M=0;
for(int i=1;i<=n;i++){
if(!visitado[i]){
dfs(i),gaux.pb(i);
}
}
clr(visitado);
M=0;
for(int i=gaux.size()-1;i>=0;i--){
if(!visitado[gaux[i]]){
dfs(gaux[i]);
M++;
}
}
cout<<M<<endl;
}
}

31

CAPTULO 6. GRAFOS

6.8.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

Componentes Fuertemente Conexas (Kosaraju)

#include
#include
#include
#include

<cstdio>
<vector>
<cstring>
<fstream>

#define MAX 2005


using namespace std;
vector<int> g[MAX], gt[MAX];
vector<int> S;//para el topsort
int N,M;// nodos, edges
int numSCC;
bool vis[MAX];
int scc[MAX];// Para asignar scc correspondiente
void dfs(int u, int pass) {
vis[u] = true;
vector<int> &ady = ((pass == 1)?g[u]: gt[u]);
for(int j = 0; j < ady.size(); j++) {
int v = ady[j];
if(!vis[v])
dfs(v, pass);
}
if(pass == 1) S.push_back(u);//adicionamos al topsort
else scc[u] = numSCC; // asignamos a que SCC pertenece el nodo
}
int kosaraju() {
S.clear();
memset(vis, false, sizeof(vis));
for(int i = 1; i <= N; i++)//Los nodos estan numerados de 1 - N
if(!vis[i])
dfs(i, 1);
numSCC = 0;
memset(vis, false, sizeof(vis));
memset(scc, -1, sizeof(scc));
for(int i = N-1; i >= 0; i--)
if(!vis[S[i]]) {
dfs(S[i], 2);
numSCC++;
}
return numSCC;
}
int main(){
//freopen("in", "r", stdin);
int u, v, sent;
while(scanf(" %d %d", &N, &M) and !(!N and !M)){
for(int i = 1; i <= N; i++)g[i].clear(), gt[i].clear();
while(M--){
scanf(" %d %d %d", &u, &v, &sent);
if(sent == 1){//un solo sentido
g[u].push_back(v);
gt[v].push_back(u);
}else{//Doble sentido
g[u].push_back(v);g[v].push_back(u);
gt[v].push_back(u);gt[u].push_back(v);
}

32

CAPTULO 6. GRAFOS
57
58
59
60
61

}
printf(" %d\n", kosaraju()==1);
}
return 0;
}

6.9.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

Componentes Fuertemente Conexas (Tarjan O(n + v) )

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
typedef long long lli;
typedef pair<int, int> pii;
#define LENGTH(a) ((int)a.length())
#define SIZE(a) ((int)a.size())
int const MAX = 100;
int const INF = 1000000;
class Grafo
{
public:
vector<vector<int> > L;
vector<int> num, low;
vector<bool> visitado;
vector<int> componente;
int nComponentes, numCnt;
Grafo(int n)
{
init(n);
}
void init(int n)
{
L = vector<vector<int> >(n);
num = vector<int>(n, -1);
low = vector<int>(n, 0);
visitado = vector<bool>(n, false);
componente.clear();
nComponentes = numCnt = 0;
}
void add(int a, int b)
{
L[a].push_back(b);
}
void ejecutarTarjan()
{
for (int i = 0; i < SIZE(L); ++i)
if (num[i] == -1)
tarjan(i);
}

33

CAPTULO 6. GRAFOS
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

void tarjan(int u)
{
low[u] = num[u] = numCnt++;
visitado[u] = true;
componente.push_back(u);
for (int i = 0; i < SIZE(L[u]); ++i)
{
int v = L[u][i];
if (num[v] == -1)
tarjan(v);
if (visitado[v])
low[u] = min(low[u], low[v]);
}
if (num[u] == low[u])
{
nComponentes++;
int v;
do
{
v = componente[SIZE(componente) - 1];
visitado[v] = false;
componente.erase(--componente.end());
}
while (v != u);
}
}
};
int main(){
int nodos;
cin>>nodos;
Grafo g(nodos);
//leer lados
g.ejecutarTarjan();
//g.nComponentes contiene el numero de SCC
return 0;
}
Otra implementacion:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

import java.util.*;
public class SCCTarjan {
int time;
List<Integer>[] graph;
int[] lowlink;
boolean[] used;
List<Integer> stack;
List<List<Integer>> components;
public List<List<Integer>> scc(List<Integer>[] graph) {
int n = graph.length;
this.graph = graph;
lowlink = new int[n];
used = new boolean[n];
stack = new ArrayList<>();
components = new ArrayList<>();

34

CAPTULO 6. GRAFOS
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

for (int u = 0; u < n; u++)


if (!used[u])
dfs(u);
return components;
}
void dfs(int u) {
lowlink[u] = time++;
used[u] = true;
stack.add(u);
boolean isComponentRoot = true;
for (int v : graph[u]) {
if (!used[v])
dfs(v);
if (lowlink[u] > lowlink[v]) {
lowlink[u] = lowlink[v];
isComponentRoot = false;
}
}
if (isComponentRoot) {
List<Integer> component = new ArrayList<>();
while (true) {
int k = stack.remove(stack.size() - 1);
component.add(k);
lowlink[k] = Integer.MAX_VALUE;
if (k == u)
break;
}
components.add(component);
}
}
public static void main(String[] args) {
List<Integer>[] g = new List[1000];
for (int i = 0; i < g.length; i++) {
g[i] = new ArrayList<>();
}
List<List<Integer>> components = new SCCTarjan().scc(g);
System.out.println(components);
}
}

6.10.
1
2
3
4
5
6
7
8
9

Minimum Spanning Tree (Kruskall)

#define lim 100000


using namespace std;
typedef vector<pair<int,pair<int,int> > > V;
int N,lider[lim];
V v;
void init(){
Sort(v);
for(int i=0;i<N;i++)lider[i]=i;
}

35

CAPTULO 6. GRAFOS
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

int find(int n){


if(n==lider[n])return n;
else return lider[n]=find(lider[n]);
}
int kruskall(){
int a,b,sum=0;
init();
for(int i=0;(int)i<v.sz;i++){
a=find(v[i].s.f);
b=find(v[i].s.s);
if(a!=b){
lider[b]=a;
sum+=v[i].f;
}
}
return sum;
}
//v.pb(mp(c,mp(a,b))); peso(c),arista(a,b)

6.11.

Second Minimum Spanning Tree

Segundo Mejor Arbol de Expansion Complejidad: O(V*E) , (V = nodos, E=Arcos)


Armamos el primer MST
Para cada arco en el MST el Segundo Mejor Arbol de Expansion es el minimo de:
Ignoramos ese arco
Hallamos el MST sin ese arco
No es necesario volver a ordenar por que ya se ordeno al calcular el primer MST
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

#include
#include
#include
#include
#include
#include

<cstdio>
<fstream>
<algorithm>
<vector>
<cmath>
<climits>

#define MAX 102


using namespace std;
struct UnionFind {
int p[MAX];
int r[MAX];
int n;
UnionFind(int _n) {
reset(_n);
}
void reset(int N) {
n = N;
for(int i = 0 ; i <= n ; ++i )
p[i] = i, r[i] = 0;
}
int Find(int x) {
return (p[x]==x?x:p[x]=Find(p[x]));
}
bool sameComponent(int x, int y) {

36

CAPTULO 6. GRAFOS
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

return Find(x) == Find(y);


}
void Union(int x, int y) {
int xRoot = Find(x);
int yRoot = Find(y);
if(r[xRoot] > r[yRoot])
p[yRoot] = xRoot;
else {
p[xRoot] = yRoot;
if(r[xRoot] == r[yRoot])
r[yRoot]++;
}
}
};
vector<pair<long long int, pair<int, int> > > g;
vector<int> mst;
UnionFind uf(MAX - 1);
int t, n, m, u, v;
long long int p;
long long int solve(int ign, bool guardar) {
long long int ans = 0;
uf.reset(n);
int comp = n;
for(int i = 0; i < g.size(); i++) {
if(i == ign)continue;
int a = g[i].second.first, b = g[i].second.second;
long long int p = g[i].first;
if(!uf.sameComponent(a, b)) {
uf.Union(a, b);
ans += p;
if(guardar) mst.push_back(i);
comp--;
if(comp == 1)break;
}
}
if(comp != 1)return LLONG_MAX;
return ans;
}
int main() {
freopen("in", "r", stdin);
scanf(" %d", &t);
while(t--) {
scanf(" %d %d", &n, &m);
g.clear();
while(m--) {
scanf(" %d %d %lld", &u, &v, &p);
g.push_back(make_pair(p, make_pair(u,v)));
}
sort(g.begin(), g.end());
mst.clear();
long long int first = solve(-1, true), second = LLONG_MAX;
for(int i = 0; i < mst.size(); i++)
second = min(second, solve(mst[i], false));
printf(" %lld %lld\n", first, second);
}
return 0;
}

37

CAPTULO 6. GRAFOS

6.12.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

Minimum Cut

#include <iostream>
#include <limits.h>
#include <string.h>
#include <queue>
using namespace std;
#define V 100
int bfs(int rGraph[V][V], int s, int t, int parent[])
{
bool visited[V];
memset(visited, 0, sizeof(visited));
queue <int> q;
q.push(s);
visited[s] = true;
parent[s] = -1;
while (!q.empty())
{
int u = q.front();
q.pop();
for (int v=0; v<V; v++)
{
if (visited[v]==false && rGraph[u][v] > 0)
{
q.push(v);
parent[v] = u;
visited[v] = true;
}
}
}
return (visited[t] == true);
}
void dfs(int rGraph[V][V], int s, bool visited[])
{
visited[s] = true;
for (int i = 0; i < V; i++)
if (rGraph[s][i] && !visited[i])
dfs(rGraph, i, visited);
}
void minCut(int graph[V][V], int s, int t)
{
int u, v;
int rGraph[V][V];
for (u = 0; u < V; u++)
for (v = 0; v < V; v++)
rGraph[u][v] = graph[u][v];
int parent[V];
while (bfs(rGraph, s, t, parent))
{
int path_flow = INT_MAX;
for (v=t; v!=s; v=parent[v])
{
u = parent[v];
path_flow = min(path_flow, rGraph[u][v]);

38

CAPTULO 6. GRAFOS
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

}
for (v=t; v != s; v=parent[v])
{
u = parent[v];
rGraph[u][v] -= path_flow;
rGraph[v][u] += path_flow;
}
}
bool visited[V];
memset(visited, false, sizeof(visited));
dfs(rGraph, s, visited);
int costoCorte=0;
for (int i = 0; i < V; i++)
for (int j = 0; j < V; j++)
if (visited[i] && !visited[j] && graph[i][j]){
//cout << i << " - " << j << endl;
costoCorte+=graph[i][j];
}
cout<<costoCorte<<endl;
return;
}
int main()
{
int graph[V][V];
minCut(graph, 0, 5);
return 0;
}

6.13.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

MaxFlow

#include
#include
#include
#include
#include

<algorithm>
<cstring>
<cstdio>
<limits>
<queue>

using namespace std;


#define N 1000 //maximo de nodos
//halla el flujo maximo desde el nodo s
//hasta el nodo t
//cap[][] almacena flujos parciales
int cap[N][N], padre[N], n, s, t;
bool bfs() {
queue<int> q;
q.push(s);
memset(padre, -1, sizeof padre);
padre[s] = s;
while (q.size()) {
int u = q.front();
q.pop();
if (u == t)
return true;
for (int v = 0; v < n; ++v)

39

CAPTULO 6. GRAFOS
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

if (padre[v] == -1 && cap[u][v])


padre[v] = u, q.push(v);
}
return false;
}
int maxFlow() {
int mf = 0, f, v;
while (bfs()) {
v = t;
f = numeric_limits<int>::max();
while (padre[v] != v)
f = min(f, cap[padre[v]][v]), v = padre[v];
v = t;
mf += f;
while (padre[v] != v)
cap[padre[v]][v] -= f, cap[v][padre[v]] += f, v = padre[v];
}
return mf;
}

#define capacidad(i, j, c) cap[i][j] += c, cap[j][i] += c


int main() {
int c;
printf("ingrese el numero de nodos\n");
scanf(" %d", &n);
printf("ingrese el inicio destino y nro nodos");
memset(cap, 0, sizeof cap);
scanf(" %d %d %d", &s, &t, &c);
--s, --t;
printf("ingrese los lados x y & capacidad");
for (int i = 0, x, y, z; i < c; ++i)
scanf(" %d %d %d", &x, &y, &z), capacidad(x - 1, y - 1, z);

printf("el flujo maximo entre s y t es %d\n", maxFlow());


return 0;
}

6.14.
1
2
3
4
5
6
7
8
9
10
11
12

Lowest common ancestor (LCA)

#include <cctype>
#include <cstdio>
#include <iostream>
#define NN 100048
using namespace std;
// LCA con pesos
// halla camino corto desde a hasta b con numero de consultas q
int P[NN][17], L[NN];
long long W[NN];

40

CAPTULO 6. GRAFOS
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

int query(int p, int q)


{
int log, i;
if (L[p] < L[q]) p ^= q ^= p ^= q;
for (log = 1; 1 << log <= L[p]; log++);
log--;
for (i = log; i >= 0; i--)
if (L[p] - (1 << i) >= L[q])
p = P[p][i];
if (p == q) return p;
for (i = log; i >= 0; i--)
if (P[p][i] != -1 && P[p][i] != P[q][i])
p = P[p][i], q = P[q][i];
return P[p][0];
}
int main(void)
{
int a, b, N, q;
cin>>N;//nodos
long long w;
P[0][0] = -1;
L[0] = W[0] = 0;
int lados;
cin>>lados;
int ii;//(ii<=>desde), (a<=> hasta), (w<=>peso)
for(int i = 0; i < lados; ++i)
{
cin>>ii>>a>>w;
for(int j = 0; (1 << j) < N; ++j) P[ii][j] = -1;
P[ii][0] = a;
L[ii] = L[a] + 1;
W[ii] = W[a] + w;
}
for(int j = 1; (1 << j) < N; ++j)
for(int i = 0; i < N; ++i)
if(P[i][j - 1] != -1)
P[i][j] = P[P[i][j - 1]][j - 1];
cin>>q;
while(q--)
{
cin>>a>>b;
printf(" %lld\n", W[a] + W[b] - (W[query(a, b)] << 1));
}
return 0;
}

6.15.
1
2
3
4
5
6
7
8

Maximo Emparejamiento Bipartito

#include <cstdio>
#include <list>
#include <queue>
//Emparejamiento Bipartito hasta 50000 nodos y 150000 caminos :) crazy...
using namespace std;
//MAX_N y SINK son mayores al numero de nodos

41

CAPTULO 6. GRAFOS
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

42

const int SINK = 50001;


const int MAX_N = 50005;
const int INFINITO = 87654321;
int N, M, P;
int grafo1[MAX_N], grafo2[MAX_N], dist[MAX_N];
list< int > adj[MAX_N];
bool bfs() {
queue< int > q; // cola de G1 nodes
for (int v = 0; v < N; ++v) {
if (grafo1[v] == SINK) {
dist[v] = 0;
q.push(v);
}
else {
dist[v] = INFINITO;
}
}
dist[SINK] = INFINITO;
while (!q.empty()) {
int v = q.front();
q.pop();
if (dist[v] < dist[SINK]) {
for (list< int >::iterator it = adj[v].begin(); it != adj[v].end();
++it) {
int u = *it;
if (dist[grafo2[u]] == INFINITO) {
dist[grafo2[u]] = dist[v] + 1;
q.push(grafo2[u]);
}
}
}
}
return dist[SINK] != INFINITO;
}
bool dfs(int u) {
// DFS comienza en el nodo u de G1
if (u == SINK) {
return true;
}
for (list< int >::iterator it = adj[u].begin(); it != adj[u].end(); ++it) {
int v = *it;
if (dist[grafo2[v]] == dist[u] + 1) {
if (dfs(grafo2[v])) {
grafo1[u] = v;
grafo2[v] = u;
return true;
}
}

CAPTULO 6. GRAFOS
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

}
dist[u] = INFINITO;
return false;
}
int hopcroft_karp() {
int matching = 0;
for (int i = 0;
grafo1[i] =
}
for (int j = 0;
grafo2[j] =
}

i < N; ++i) {
SINK;
j < M; ++j) {
SINK;

while (bfs()) {
for (int i = 0; i < N; ++i) {
if (grafo1[i] == SINK) {
matching += dfs(i);
}
}
}
return matching;
}
int main() {
// inside in main() ggg al estilo halim
//N primer conjunto
//M segundo conjunto
//P numero de relaciones (arcos)
scanf(" %i %i %i", &N, &M, &P);
//clear
for (int i = 0; i < N; ++i) {
adj[i] = list< int >();
}
for (int i = 0; i < P; ++i) {
int u, v;
scanf(" %i %i", &u, &v);
--u; --v;
adj[u].push_back(v);
}
printf(" %i\n", hopcroft_karp());
return 0;
}

6.16.
1
2
3
4
5
6

43

Puentes

import java.util.*;
public class Bridges {
static int time;
static List<Integer>[] graph;

CAPTULO 6. GRAFOS
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

static
static
static
static

static void dfs(int u, int p) {


used[u] = true;
lowlink[u] = tin[u] = time++;
for (int v : graph[u]) {
if (v == p) {
continue;
}
if (used[v]) {
// lowlink[u] = Math.min(lowlink[u], lowlink[v]);
lowlink[u] = Math.min(lowlink[u], tin[v]);
} else {
dfs(v, u);
lowlink[u] = Math.min(lowlink[u], lowlink[v]);
if (lowlink[v] > tin[u] && p != -1) {
bridges.add("(" + u + "," + v + ")");
}
}
}
}
public static void main(String[] args) {
time = 0;
int n = 6;
graph = new List[n];
for (int i = 0; i < n; i++) {
graph[i] = new ArrayList<>();
}
used = new boolean[n];
tin = new int[n];
lowlink = new int[n];
bridges = new ArrayList<>();
dfs(0, -1);
System.out.println(bridges);
}
}

6.17.
1
2
3
4
5
6
7
8
9
10
11
12
13

boolean[] used;
int[] tin;
int[] lowlink;
List<String> bridges;

Puntos de Articulacin

import java.util.*;
public class ArticulationPoints {
static
static
static
static
static
static

int time;
List<Integer>[] grafo;
boolean[] vis;
int[] tin;
int[] dfsLow;
List<Integer> puntosArticulacion;

static void dfs(int u, int p) {


vis[u] = true;

44

CAPTULO 6. GRAFOS
dfsLow[u] = tin[u] = time++;
int child = 0;
for (int v : grafo[u]) {
if (v == p) {
continue;
}
if (vis[v]) {
dfsLow[u] = Math.min(dfsLow[u], tin[v]);
} else {
dfs(v, u);
dfsLow[u] = Math.min(dfsLow[u], dfsLow[v]);
if (dfsLow[v] >= tin[u] && p != -1) {
puntosArticulacion.add(u);
}
++child;
}
}
if (p == -1 && child > 1) {
puntosArticulacion.add(u);
}

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

}
public static void main(String[] args) {
time = 0;
int n = 5;
grafo = new List[n];
for (int i = 0; i < n; i++) {
grafo[i] = new ArrayList<>();
}
vis = new boolean[n];
tin = new int[n];
dfsLow = new int[n];
puntosArticulacion = new ArrayList<>();
dfs(0, -1);
//System.out.println(puntosArticulacion); si puntosArticulacion == null
entonces es un grafo biconexo
}
}

6.18.
1
2
3
4
5
6
7
8
9
10
11
12
13

Camino Euleriano

list<int> cyc;
void EulerTour(list<int>::iterator i, int u){
for(int j = 0; j < grafo[u].size(); j++){
pair<int,int> v = grafo[u][j];
if(v.second){
v.second = 0;
for(int k = 0; k < grafo[v.first].size(); k++){
pair<int,int> uu = grafo[v.first][k];
if(uu.first == u && uu.second){
uu.second = 0;
break;
}
}

45

CAPTULO 6. GRAFOS
14
15
16
17
18
19
20
21
22
23
24

EulerTour(cyc.insert(i, u), v.first);


}
}
}
int main(){
cyc.clear();
EulerTour(cyc.begin(), ini);
for(list<int>::iterator it = cyc.begin(); it != cyc.end(); it++)
cout << (*it) << endl;
return 0;
}

6.19.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Dijkstra Fast

vector<int> dist(n, INF); dist[S] = 0;


queue<int> q; q.push(S);
vector<int> in_queue(n, 0); in_queue[S] = 1;
while (!q.empty()) {
int u = q.front(); q.pop(); in_queue[u] = 0;
for (j = 0; j < (int)AdjList[u].size(); j++) {
int v = AdjList[u][j].first, weight_u_v = AdjList[u][j].second;
if (dist[u] + weight_u_v < dist[v]) {
dist[v] = dist[u] + weight_u_v;
if (!in_queue[v]) { //Agregamos a la cola solo si no esta en la cola
q.push(v);
in_queue[v] = 1;
}
}
}
}
if (dist[T] != INF) printf(" %d\n", dist[T]);
else
printf("unreachable\n");

46

Captulo 7

Matemticas
7.1.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

//Entrada: Dos enteros a y b


//Salida: El maximo comun divisor entre a y b
#include <algorithm>
int gcd (int a, int b){
__gcd(a,b);
}
int gcd (int a, int b){
return b==0?a:gcd(b, a % b);
}
int gcd (int a, int b){
int c = a % b;
while(c != 0){
a = b;
b = c;
c = a % b;
}
return b;
}

7.2.
1
2
3
4
5

LCM

//Entrada: Dos enteros a y b


//Salida: El minimo comun multiplo entre a y b
int lcm (int a, int b) {
return a / gcd (a, b) * b;
}

7.3.
1
2
3
4
5

GCD

Algoritmo extendido de euclides

/*Permite encontrar los coeficientes (x, y) mas pequenios de:


ax + by = gcd(a, b);
*/
int x, y;//Al terminar la sol estara aqui
void solve(int a, int b){
47

CAPTULO 7. MATEMTICAS
6
7
8
9
10
11
12

if(b == 0){x = 1; y = 0; d = a; return;}


solve(b, a % b);
int x1 = y;
int y1 = x - (a / b) * y;
x = x1;
y = y1;
}

7.4.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

Exponenciacin rapida

long long int pow(int b, int e){


if(!e) return 1;
long long int ans = pow(b, e>>1);
ans *= ans;
if(e&1)
ans *= b;
return ans;
}
unsigned long long int modpow(long long int b, int e, int m){
if(!e) return 1;
unsigned long long int ans = modpow(b, e>>1, m);
ans = (ans * ans) % m;// cuidado con desborde en la multiplicacion
if(e&1)
ans = (ans * b) % m;
return ans;
}
//podemos utilizar una idea similar para evitar el desborde en la multiplicacion
int multi(long long a, long long b, long long mod){
if(b == 0) return 0;
long long int ans = (multi( a, b / 2, mod ) * 2) % mod;
if( b % 2 == 1 ) ans = (ans + a) % mod;
return ans;
}

7.5.
1
2
3
4
5
6
7
8
9
10
11
12
13

48

Criba de Erathostenes

#include <vector>
#include <bitset>
#define MAXPRIME 3162300 // raiz de maximo numero que manejaremos
using namespace std;
bitset<MAXPRIME> criba;
vector<long long int> primos;
void llena_criba()
{
criba.set();// marcamos todo como false

CAPTULO 7. MATEMTICAS
14
15
16
17
18
19
20
21

for (int i = 2; i < MAXPRIME; i++)


if (criba.test( i ))
{
primos.push_back( i );
for (int j= i + i; j<MAXPRIME; j += i)
criba.reset( j );
}
}

7.6.

scanf(" %llu %llu", &a, &b);


if(a <= 1)a = 2;//Causa error con en 1 (No es primo)
fill(p2, p2 + MAX, true);
int ptr = 0;
while(primos[ptr] * primos[ptr] <= b) {
unsigned long long int ini = a;
if(a % primos[ptr] != 0 ) ini += (primos[ptr] - (a % primos[ptr]));//el
siguiente multiplo de primos[ptr]
if(ini <= primos[ptr]) ini += primos[ptr];//Si es primo
while(ini <= b) {
p2[ini - a] = false;
ini += primos[ptr];
}
ptr++;
}
unsigned long long int ans = 0, primos = 0;
for(unsigned long long int i = a; i <= b; i++)
if(p2[i - a])
primos++;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

7.7.
1
2
3
4
5
6
7
8
9
10
11
12
13

Triangulo de Pascal

#define MAXN 100 // largest n or m


int n,m;
long binomial_coefficient(n,m){
int i,j;
long bc[MAXN][MAXN];
for (i=0; i<=n; i++) bc[i][0] = bc[i][i] = 1;
for (i=1; i<=n; i++)
for (j=1; j<i; j++)
bc[i][j] = bc[i-1][j-1] + bc[i-1][j];
return bc[n][m];
}

7.8.
1
2
3

Criba de Erathostenes Aumentada

Combinaciones(Para numeros muy grandes)

unsigned long long C(int n, int k) {


k = min(k,n-k);
unsigned long long res = 1;

49

CAPTULO 7. MATEMTICAS
4
5
6
7
8
9
10

for(int i = 0; i < k; i++)


{
res *= (n-i);
res /= (i+1);
}
return res;
}

7.9.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

Polinomios

class Polinomio {
double[] coef;
// a0 + a1x + a2x^2 + ...
public Polinomio(double[] coef) {
this.coef = coef;
}
public double integrar(double a, double b) {
Polinomio integ = integral();
return integ.evaluar(b) - integ.evaluar(a);
}
public double evaluar(double x) {
double result = 0;
for (int i = coef.length - 1; i >= 0; i--)
result = coef[i] + x*result;
return result;
}
public Polinomio integral() {
double[] newCoef = new double[coef.length + 1];
newCoef[0] = 0;
for (int i = 1; i < newCoef.length; i++)
newCoef[i] = coef[i-1]/i;
return new Polinomio(newCoef);
}
public Polinomio cuadrado() {
double[] newCoef = new double[coef.length * 2 - 1];
for (int i = 0; i < newCoef.length; i++)
for (int j = 0; j <= i; j++)
if (j < coef.length && i - j < coef.length)
newCoef[i] += coef[j] * coef[i-j];
return new Polinomio(newCoef);
}
public Polinomio multiplicar(double c) {
double[] newCoef = new double[coef.length];
for (int i = 0; i < newCoef.length; i++)
newCoef[i] = coef[i] * c;
return new Polinomio(newCoef);
}
}

50

CAPTULO 7. MATEMTICAS

7.10.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

//Entrada: Un entero n
//Salida: El n-esimo fibonacci en tiempo O(log(n))
long long int fibo(int n) {
long long int a,b,x,y,tmp;
a = x = tmp = 0;
b = y = 1;
while(n!=0)
if(n %2 == 0) {
tmp = a*a + b*b;
b = b*a + a*b + b*b;
a = tmp;
n = n/2;
} else {
tmp = a*x + b*y;
y = b*x + a*y + b*y;
x = tmp;
n = n-1;
}
// x = fibo(n-1)
return y;// y = fibo(n)
}

7.11.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

Fibonacci ( O(log(n)) )

Multiplicacin entero por cadena

//Entrada: Una cadena y un numero entero


//Salida: La multiplicacion de la cadena con el numero
#include <iostream>
#include <string.h>
using namespace std;
unsigned int c,i,n;
char res[1000];
void multi(int n){
for(c = i = 0; res[i]; i++){
c = (res[ i ] - 0) * n + c;
res[ i ] = c % 10 + 0;
c /= 10;
}
while( c ){
res[ i++ ] = 0 + c % 10;
c /= 10;
}
res[i] = 0;
}
int main(){
string cad;
int m;
cin >> cad;
cad = string(cad.rbegin(), cad.rend());
strcpy(res, cad.c_str());

51

CAPTULO 7. MATEMTICAS
31
32
33
34
35
36
37
38

multi(m);
string r(res);
string sal(r.rbegin(), r.rend());
cout << sal << endl;
return 0;
}

7.12.

Multiplicacin de numeros grandes (Karatsuba)

//Entrada: 2 BigIntegers x e y
//Salida: La multplicacion de x e y
import java.math.BigInteger;
class Karatsuba {
private final static BigInteger ZERO = new BigInteger("0");
public static BigInteger karatsuba(BigInteger x, BigInteger y) {
int N = Math.max(x.bitLength(), y.bitLength());
if (N <= 2000) return x.multiply(y);
N = (N / 2) + (N % 2);
BigInteger b = x.shiftRight(N);
BigInteger a = x.subtract(b.shiftLeft(N));
BigInteger d = y.shiftRight(N);
BigInteger c = y.subtract(d.shiftLeft(N));
BigInteger ac = karatsuba(a, c);
BigInteger bd = karatsuba(b, d);
BigInteger abcd = karatsuba(a.add(b), c.add(d));
return ac.add(abcd.subtract(ac).subtract(bd).shiftLeft(N)).add(bd.
shiftLeft(2*N));
18
}
19 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

7.13.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Integracion de Simpson

double a[12];
int n;
double f(double x){
double ans = 0;
for(int i = 0; i <= n; i++)
ans += (a[i] * pow(x,i));
return ans*ans*PI;
}
double S(double a, double b, double c, double h){
return (h / 3.0) * ( f(a) + 4.0 * f(c) + f(b));
}
double SIMP(double a, double b, double E ){
double h = (b-a)/2.0,
c = (b+a)/2.0;
double a1 = a,
a2 = c,

b1 = c,
b2 = b;

52

CAPTULO 7. MATEMTICAS
21
22
23
24
25
26
27
28
29

double c1 = (b1+a1)/2.0,
c2 = (b2+a2)/2.0;
double L = (S(a1,b1, c1,h) + S(a2,b2,c2,h)) / 2.0;
if(0.1*abs(L-S(a,b,c,h)) < E)
return L;
else
return SIMP(a1,b1, E/2.0) + SIMP(a2,b2, E/2.0);
}

7.14.

Inverso modular

Si queremos hallar a/b(mod p) donde p es primo, es lo mismo que:


(a b1 )(mod p)
donde b1 es el inverso modular de b .
Para hallar el inverso modular de un numero xmodulo p:
x1 (mod p) = modpow(x, p 2, p)
Entonces, volviendo al problema:
a/b(mod p) = (a modpow(b, p 2, p)

7.15.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#include <cstdio>
int main() {
int N;
while (scanf(" %d", &N) && N) {
int b = 0;
while (N--) {
int v;
scanf(" %d", &v);
b ^= v;
}
puts(b ? "Yes" : "No");
}
return 0;
}

7.16.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

El juego de Nim

Fraccion

/////////////////////////////////////////////////////////////////////
//Fraction.
/////////////////////////////////////////////////////////////////////
using namespace std;
typedef long long Num;
Num gcd(Num a, Num b) {
Num temp;
if (a < b) {
temp = a;
a = b;
b = temp;

53

CAPTULO 7. MATEMTICAS
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

}
do {
temp = a % b;
a = b;
b = temp;
} while (b != 0);
return a;
}
struct Fraction {
Num up;
Num down;
Fraction(Num _up = 1, Num _down = 1) {
up = _up;
down = _down;
}
void reduce() {
if (up != 0) {
Num div = up > 0? gcd(up, down): gcd(-up, down);
up /= div;
down /= div;
}
else {
down = 1;
}
}
Fraction operator + (const Fraction& add) const {
Fraction result(up * add.down + down * add.up, down * add.down);
result.reduce();
return result;
}
Fraction operator - (const Fraction& sub) const {
Fraction result(up * sub.down - down * sub.up, down * sub.down);
result.reduce();
return result;
}
Fraction operator * (const Fraction& mul) const {
Fraction result(up * mul.up, down * mul.down);
result.reduce();
return result;
}
Fraction operator / (const Fraction& div) const {
Fraction result(up * div.down, down * div.up);
result.reduce();
return result;
}
bool operator == (Num i) const {
return up % down == 0 && up / down == i;
}
bool operator != (Num i) const {

54

CAPTULO 7. MATEMTICAS
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

return !(*this == i);


}
void operator = (Num i) {
up = i;
down = 1;
}
};
//Test suite.
#include <iostream>
ostream& operator << (ostream& os, const Fraction& f) {
if (f.down != 1) {
os << f.up << "/" << f.down;
}
else {
os << f.up;
}
return os;
}
int main () {
typedef Fraction F;
Fraction f[] = {F(2, 3), F(5, 7), F(9, 6), F(3, 4), F(125, 63)};
Fraction result = (f[0] + f[1] * f[2]) / f[3];
cout << result << " ";
result = result - f[4];
cout << result << " " << (result == 1) << " " << (result != 0) << endl;
//Correct output: 146/63 1/3 0 1;
return 0;
}

7.17.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

Matriz

#define MOD 1000000007


#define MAXN 16
int size;
struct Matrix {
int X[MAXN][MAXN];
Matrix () {}
Matrix (int k) {
memset(X, 0, sizeof(X));
for(int i=0; i<size; i++)
X[i][i] = k;
}
};
Matrix operator *(Matrix &A, Matrix &B) {
Matrix M;
for(int i=0; i<size; i++) {
for(int j=0; j<size; j++) {
long long tmp = 0;

55

CAPTULO 7. MATEMTICAS
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

for(int k=0; k<size; k++)


tmp += (long long)A.X[i][k] * B.X[k][j];
M.X[i][j] = tmp % MOD;
}
}
return M;
}
Matrix pow(Matrix x, long long n) {
Matrix P(1);
while(n) {
if(n & 1) P = P * x;
n >>= 1;
x = x * x;
}
return P;
}
long long modpow(long long x, long long n) {
long long P = 1;
while(n) {
if(n & 1) P = P * x % MOD;
n >>= 1;
x = x * x % MOD;
}
return P;
}

7.18.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

Gauss Jordan

class fraction {public:


L n, d;
fraction(L n,L d) {
this->n=n;
this->d=d;
simplify();
}
void simplify(){
L g=__gcd(abs(n),abs(d));
n/=g;
d/=g;
if(n==0) d=1;
if(n<1 && d<1) {
n = abs(n);
d = abs(d);
} else if (n<1 || d<1) {
n=abs(n);
d=abs(d);
n =-n;
}
}
fraction inverse(){
return fraction(d,n);
}
fraction() {
n=0;
d=1;

56

CAPTULO 7. MATEMTICAS
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

}
fraction operator/(const fraction& f) {
fraction ret(n*f.d,d*f.n);
return ret;
}
fraction operator*(const fraction& f) {
fraction ret(n*f.n,d*f.d);
return ret;
}
fraction operator+(const fraction& f) {
fraction ret((n*f.d)+(f.n*d),d*f.d);
return ret;
}
fraction operator*(L x) {
fraction ret(x*n,d);
return ret;
}
fraction operator-() {
fraction ret(-n,d);
return ret;
}
fraction operator-(const fraction& f) {
fraction ret((n*f.d)-(f.n*d),d*f.d);
return ret;
}
bool operator>(const fraction& f) {
return abs(n*f.d)>abs(f.n*d);
}
fraction read(){
char c;
scanf(" %lld",&n);
d = 1;
scanf(" %c",&c);
if(c==/)
scanf(" %lld",&d);
}
void print(){
if(d==1) {
printf(" %lld\n",n);
} else {
printf(" %lld/ %lld\n",n,d);
}
}
};
bool hasSol;
int rankA,rankAC;
const int MX = 59;
vector<fraction> mat[MX];
fraction x[MX];
int N,Y,X,nunk;
void gauss() {
for(int p=1;p<=nunk;p++) {
int maxR=p;
for(int y=p+1;y<=Y;y++)

57

CAPTULO 7. MATEMTICAS
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

58

if(mat[y][p] > mat[maxR][p])


maxR=y;
swap(mat[p],mat[maxR]);
if(mat[p][p].n == 0)
continue;
fraction t = mat[p][p].inverse();
for(int i=1;i <= X;i++)
mat[p][i] = mat[p][i] * t;
for(int y=p+1;y<=Y;y++){
t = -mat[y][p];
for(int j=1;j <= X;j++) {
mat[y][j] = mat[y][j] + (t*mat[p][j]);
}
}
}
}
void rank() {
rankA=rankAC=Y;
bool allZeroes;
for(int y=1;y<=Y;y++) {
allZeroes=true;
for(int j=1;allZeroes and j <= nunk;j++)
if(mat[y][j].n != 0)
allZeroes=false;
if(allZeroes) {
rankA--;
if(mat[y][nunk+1].n == 0)
rankAC--;
}
}
}
void resuelva(){
L num,den;
char c;
scanf(" %d %d",&nunk,&Y);
X = nunk + 1;
for(int y=1;y <= Y;y++)
for(int x=1;x <= X;x++)
mat[y][x].read();
hasSol=true;
gauss();
rank();
if(rankAC != rankA){
printf("No Solution.\n");
} else {
if(rankAC<nunk)
printf("Infinitely many solutions containing %d arbitrary constants.\n"
,nunk-rankAC);
else{
for(int p=nunk;p>=1;--p) {

CAPTULO 7. MATEMTICAS
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165

fraction s(0,1);
for(int k=p+1;k<=nunk;++k)
s = s + (x[k]*mat[p][k]);
x[p] = (mat[p][X]-s) / mat[p][p];
}
for(int y=1;y<=nunk;y++)
printf("x[ %d] = ",y),x[y].print();
}
}
}
int main() {
int nc;
bool first=true;
for(int i=0;i<MX;i++)
mat[i].resize(MX);
while(scanf(" %d",&N) and N>0) {
if(first == false) printf("\n");first = false;
printf("Solution for Matrix System # %d\n",N);
resuelva();
}
}

7.19.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

59

Numeros romanos

string AtoR(int A){


map<int, string> cvt;
cvt[1000] = "M"; cvt[900] = "CM"; cvt[500] = "D"; cvt[400] = "CD";
cvt[100] = "C"; cvt[90] = "XC"; cvt[50] = "L"; cvt[40] = "XL";
cvt[10]
= "X"; cvt[9]
= "IX"; cvt[5]
= "V"; cvt[4]
= "IV";
cvt[1]
= "I";
string ans = "";
for(map<int,string>::reverse_iterator i = cvt.rbegin(); i != cvt.rend(); i++)
while(A >= (i->first)){
ans = ans + (i->second);
A -= i->first;
}
return ans;
}
int RtoA(char R[]){
map<char, int> RtoA;
RtoA[I] = 1;
RtoA[V] = 5;
RtoA[X] = 10;
RtoA[L] = 50;
RtoA[C] = 100; RtoA[D] = 500; RtoA[M] = 1000;
int value = 0;
for(int i = 0; R[i]; i++)
if(R[i+1] && RtoA[R[i]] < RtoA[R[i+1]]){
value += RtoA[R[i+1]] - RtoA[R[i]];
i++;
}else
value += RtoA[R[i]];
return value;
}

Captulo 8

Cadenas
8.1.
1
2
3

Utilidades

bool is_palindrome(string &ss){


return equal(ss.begin(), ss.end(), ss.rbegin());
}

8.2.

Boyer Moore

Encuentra todos los match de un patron en el texto.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

#include <iostream>
#include <cstring>
using namespace std;
int M, N;
//M tamanio del patron
//N tamanio del texto
void preBM(char P[], int bmNext[])
{
for(int i = 0; i <= 255; i++)
bmNext[i] = M;
for(int i = 0; i < M; i++)
bmNext[P[i]] = M - 1 - i ;
}
void Boyer_Moore(char T[], char P[])
{
int i = M - 1;
int j = M - 1;
int bmNext[255];
preBM(P,bmNext);
while((i < N) && (j >= 0))
{
if(T[i] == P[j])
{
i--;
j--;
}
60

CAPTULO 8. CADENAS
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

else
{
i += bmNext[T[i]];
j = M - 1;
}
if(j < 0)
{
cout<<"Match en: "<<(i + 1)<<endl;
i += M + 1;
j = M - 1;
}
}
}
int main()
{
char texto[100];
char patron[100];
cin>>texto;
cin>>patron;
M=strlen(patron);
N=strlen(texto);
Boyer_Moore(texto,patron);
return 0;
}

8.3.

Knuth Morris Pratt

//Entrada: Una cadena S y el patron k


//Salida: El numero de ocurrencia del patron k en S
int KMP(string S, string K)
{
vector<int> T(K.size() + 1, -1);
for(int i = 1; i <= K.size(); i++)
{
int pos = T[i - 1];
while(pos != -1 && K[pos] != K[i - 1]) pos = T[pos];
T[i] = pos + 1;
}
vector<int> matches;
int sp = 0;
int kp = 0;
while(sp < S.size())
{
while(kp != -1 && (kp == K.size() || K[kp] != S[sp])) kp = T[kp];
kp++;
sp++;
if(kp == K.size()) matches.push_back(sp - K.size());
}
/* En el vector matches se guardan los ndices a cada una de las
ocurrencias, por tanto el tamanio de dicho vector nos dir cuntas
ocurrencias se han encontrado. */
23
return matches.size();
24 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

61

CAPTULO 8. CADENAS

8.4.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

62

Iesima permutacin

//Entrada: Una cadena cad(std::string), un long th


//Salida : La th-esima permutacion lexicografica de cad
string ipermutacion(string cad, long long int th){
sort(cad.begin(), cad.end());
string sol = "";
int pos;
for(int c = cad.size() - 1; c >= 0; c--){
pos = th / fact[c];
th %= fact[c];
sol += cad[pos];
cad.erase(cad.begin() + pos);
}
return sol;
}

8.5.

Algoritmo de Manacher

El algoritmo guarda el tamao del palindrome mas grande en LP[pos] que tiene como centro las posicin pos en la
cadena original
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

#include <iostream>
#include <vector>
#include <fstream>
#include <string.h>
#define MAXN 20100
using namespace std;
int N,i,j,izq,der,posi,dist;
string cad,tmp;
char v[MAXN];
int pos[MAXN];
void todoslosPalindromos(vector<int> &LP, int par){
izq = der = -1;
for(posi = 0; posi < N; posi++){
dist = 0;
if(posi <= der)
dist = min(der - posi + par, LP[izq+der-(posi+par)]) + 1;
while(posi-dist>=0 && posi+dist-par<N
&& v[posi-dist]==v[posi+dist-par])
dist++;
LP[posi] = --dist;
if(posi+dist-par > der){
der = posi + dist - 1;
izq = posi - dist ;
}
}
}
int main() {
getline(fin,cad);
while(getline(fin,tmp))
cad +=\n+tmp;
N = 0;
for(i = 0; i < cad.length(); i++)

CAPTULO 8. CADENAS
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

63

if(isalpha(cad[i])){
v[N] = tolower(cad[i]);
pos[N] = i;
N++;
}
v[N] = \0;
vector<int> LP(N,0),LI(N,0);
todoslosPalindromos(LP,1);
todoslosPalindromos(LI,0);
int SOL1 = 0,SOL2 = 0;
//primero en los de tamanio impar
for(int i = 0; i < N; i++)
if(LI[i]*2+1 > LI[SOL1]*2+1)
SOL1 = i;
//luego en los de tamanio par
for(int i = 0; i < N; i++)
if(LP[i]*2 > LP[SOL2]*2)
SOL2 = i;
if(LI[SOL1]*2+1 > LP[SOL2]*2){
izq = SOL1 - LI[SOL1];
der = SOL1 + LI[SOL1];
}else{
izq = SOL2 - LP[SOL2];
der = SOL2 + LP[SOL2]-1;
}
fout << der - izq + 1 <<

endl;

izq = pos[izq];
der = pos[der];
fout << cad.substr(izq,der-izq+1)<<endl;
return 0;
}
Otra implementacion:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#define MAXN 600005


char str[MAXN];
int rad[MAXN];
int n;
/*
En rad se guarda el tamanio del palindromo
str[0]=$;
// si o si
scanf(" %s", str+1); // puntero para iniciar desde 1
n=strlen(str+1);
*/
void Manacher() {
int i, j, k;
i = 1;
j = 0;
while (i <= n) {
while (str[i - j] == str[i + j + 1] && i - j > 0 && i + j + 1 <= n) j++;
rad[i] = j;
k = 1;
while (k <= rad[i] && rad[i - k] != rad[i] - k) {
rad[i + k] = min(rad[i - k], rad[i] - k);
k++;
}

CAPTULO 8. CADENAS
23
24
25
26

i = i + k;
j = max(j - k, 0);
}
}

8.6.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int longestCommonSubsequence(const string& a, const string& b) {
int A = a.size(), B = b.size();
int L[2][B + 1];
for (int i = 0; i <= 1; ++i) L[i][0] = 0;
for (int i = 0; i <= B; ++i) L[0][i] = 0;
for (int i = 1; i <= A; ++i) {
int this_i = i % 2, pre_i = this_i ? 0 : 1;
for (int j = 1; j <= B; ++j) {
if (a[i - 1] == b[j - 1]) L[this_i][j] = 1 + L[pre_i][j - 1];
else L[this_i][j] = max(L[pre_i][j], L[this_i][j - 1]);
}
}
return max(L[0][B], L[1][B]);
}
int main() {
string a, b;
cin >> a >> b;
cout << longestCommonSubsequence(a, b);
}

8.7.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Longest Common Subsequence (LCS)

Suffix Array

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <cmath>
#include <string>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <utility>
#include <list>
#include <set>
#include <map>
using namespace std;
#define MAXN 1000005

64

CAPTULO 8. CADENAS
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

65

int n,t; //n es el tamanio de la cadena


int m,tam1;
set<string> orde;
int p[MAXN],r[MAXN],h[MAXN];
//r indices del sa para mostrar indice
s.substr(r[i])
//p es el inverso del suffix array, no usa indices del suffix array ordenado
//h el el tamanio del lcp entre el i-esimo y el i+1-esimo elemento de suffix
array ordenado
char s[250000];
char s2[250000];
void fix_index(int *b, int *e) {
int pkm1, pk, np, i, d, m;
pkm1 = p[*b + t];
m = e - b; d = 0;
np = b - r;
for(i = 0; i < m; i++) {
if (((pk = p[*b+t]) != pkm1) && !(np <= pkm1 && pk < np+m)) {
pkm1 = pk;
d = i;
}
p[*(b++)] = np + d;
}
}
bool comp(int i, int j) {
return p[i + t] < p[j + t];
}
void suff_arr() {
int i, j, bc[256];
t = 1;
for(i = 0; i < 256; i++) bc[i] = 0; //alfabeto
for(i = 0; i < n; i++) ++bc[int(s[i])]; //counting sort inicial del alfabeto
for(i = 1; i < 256; i++) bc[i] += bc[i - 1];
for(i = 0; i < n; i++) r[--bc[int(s[i])]] = i;
for(i = n - 1; i >= 0; i--) p[i] = bc[int(s[i])];
for(t = 1; t < n; t *= 2) {
for(i = 0, j = 1; i < n; i = j++) {
while(j < n && p[r[j]] == p[r[i]]) ++j;
if (j - i > 1) {
sort(r + i, r + j, comp);
fix_index(r + i, r + j);
}
}
}
}
void lcp() {
int tam = 0, i, j;
for(i = 0; i < n; i++)if (p[i] > 0) {
j = r[p[i] - 1];
while(s[i + tam] == s[j + tam]) ++tam;
h[p[i] - 1] = tam;
if (tam > 0) --tam;
}
h[n - 1] = 0;
}
int owner(int idx){
return (idx < n-m-1) ? 1 : 2;

CAPTULO 8. CADENAS
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

}
int main(){
freopen("760.in","r",stdin);
bool sw=false;
while(scanf(" %s",&s)==1){
scanf(" %s",&s2);
strcat(s,"$");
tam1=strlen(s);
strcat(s,s2);
strcat(s,"#");
n =strlen(s);
m=strlen(s)-tam1;
suff_arr();
lcp();
int dev=0;
string dev2;
orde.clear();
for(int i=0;i<n;i++){
if(owner(r[i]) != owner(r[i-1])){
//por si quiere mostrat $ o #
if(h[i-1] >= dev){
dev=h[i-1];
//cout<<r[i]<<" --- "<<h[i-1]<<endl;
string aux="",aux2="";
for(int j=0;j<dev;j++){
aux2=s[r[i]+j];
aux+=aux2;
}
orde.insert(aux);
}
}
}
if(sw)
printf("\n");
sw = true;
if(dev == 0)
printf("No common sequence.\n");
else{
set<string>::iterator it=orde.begin();
for (;it!=orde.end(); it++){
if((*it).size()==dev)cout <<*it<< endl;
}
}
}
return 0;
}
//rotacion menor lexicografica
/*
int tam1=strlen(s);
for(int i=tam1;i<2*tam1;i++)s[i]=s[i-tam1];
n=2*tam1;
suff_arr();
char dev[tam1];
for(int i=0;i<n;i++)
if(r[i]<tam1){
for(int j=r[i];j<r[i]+tam1;j++)
dev[j-r[i]]=s[j];

66

CAPTULO 8. CADENAS
135
136
137
138
139
140
141
142
143
144
145
146
147

break;
}
for(int i=0;i<tam1;i++)
printf(" %c",dev[i]);
*/
/*
ACM 2009 File Recover
Solucion
Problema: Contar los substrings q se repiten al menos una vez.
Analisis: Notamos que si el lcp(i,i+1) con lcp(i+1,i+2) aumenta
quiere decir que encontramos h[i+1]-h[i] palabras nuevas (prefijos)
SUM(max(h[i+1]-h[i],0))
*/

8.8.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

Suffix Array DC3

//from http://blog.csdn.net/acdreamers/article/details/10746023
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
const int N=250005;
struct State
{
State *pre,*go[26];
int step;
void clear()
{
pre=0;
step=0;
memset(go,0,sizeof(go));
}
}*root,*last;
State statePool[N*2],*cur;
void init()
{
cur=statePool;
root=last=cur++;
root->clear();
}
void Insert(int w)
{
State *p=last;
State *np=cur++;
np->clear();
np->step=p->step+1;
while(p&&!p->go[w])
p->go[w]=np,p=p->pre;
if(p==0)
np->pre=root;
else

67

CAPTULO 8. CADENAS
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

{
State *q=p->go[w];
if(p->step+1==q->step)
np->pre=q;
else
{
State *nq=cur++;
nq->clear();
memcpy(nq->go,q->go,sizeof(q->go));
nq->step=p->step+1;
nq->pre=q->pre;
q->pre=nq;
np->pre=nq;
while(p&&p->go[w]==q)
p->go[w]=nq, p=p->pre;
}
}
last=np;
}
char A[N],B[N];
int main()
{
int n,m;
scanf(" %s %s",A,B);
n=strlen(A);
m=strlen(B);
init();
for(int i=0; i<n; i++)
Insert(A[i]-a);
int ans=0,len=0;
State *p=root;
for(int i=0; i<m; i++)
{
int x=B[i]-a;
if(p->go[x])
{
len++;
p=p->go[x];
}
else
{
while(p&&!p->go[x]) p=p->pre;
if(!p) p=root,len=0;
else
len=p->step+1,p=p->go[x];
}
ans=max(ans,len);
}
printf(" %d\n",ans);
return 0;
}

8.9.
1
2

Minima Rotacion Lexicografica

/*
Rotacion Lexicografica minima MinRotLex(cadena,tamanio)

68

CAPTULO 8. CADENAS
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

para cambiar inicio de la cadena char s[300]; int h; s+h;


retorna inicio de la rotacion minima :D
*/
int MinRotLex(const char *s, const int slen) {
//for(int j=0;j<slen;j++){
//
cout<<s[j];
// }
int i = 0, j = 1, k = 0, x, y, tmp;
while(i < slen && j < slen && k < slen) {
x = i + k;
y = j + k;
if(x >= slen) x -= slen;
if(y >= slen) y -= slen;
if(s[x] == s[y]) {
k++;
} else if(s[x] > s[y]) {
i = j+1 > i+k+1 ? j+1 : i+k+1;
k = 0;
tmp = i, i = j, j = tmp;
} else {
j = i+1 > j+k+1 ? i+1 : j+k+1;
k = 0;
}
}
return i;
}
int main(){
int n;
scanf(" %d",&n);getchar();
while(n--){
char str[10009];
gets(str);
printf(" %d\n",Minlex(str,strlen(str))+1);
}
}

8.10.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Trie

#include <iostream>
#include <vector>
using namespace std;
struct Node{
char content;
bool wordMarker;
vector<Node*> children;
Node() { content = ; wordMarker = false; }
void setContent(char c) { content = c; }
void setWordMarker() { wordMarker = true; }
Node* findChild(char c);
void appendChild(Node* child) { children.push_back(child); }
};

struct Trie {
Node* root;
Trie(){root=new Node();}
void addWord(string s);

69

CAPTULO 8. CADENAS
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

bool searchWord(string s);


void deleteWord(string s);
};
Node* Node::findChild(char c){
for ( int i = 0; i < children.size(); i++ ){
Node* tmp = children.at(i);
if ( tmp->content == c )
{
return tmp;
}
}
return NULL;
}

void Trie::addWord(string s){


Node* current = root;
if ( s.length() == 0 ){
current->setWordMarker();
return;
}
for ( int i = 0; i < s.length(); i++ ){
Node* child = current->findChild(s[i]);
if ( child != NULL ){
current = child;
}else{
Node* tmp = new Node();
tmp->setContent(s[i]);
current->appendChild(tmp);
current = tmp;
}
if ( i == s.length() - 1 )
current->setWordMarker();
}
}

bool Trie::searchWord(string s)
{
Node* current = root;
while ( current != NULL )
{
for ( int i = 0; i < s.length(); i++ )
{
Node* tmp = current->findChild(s[i]);
if ( tmp == NULL )
return false;
current = tmp;
}
if ( current->wordMarker )
return true;
else

70

CAPTULO 8. CADENAS
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

return false;
}
return false;
}

int main(){
Trie* trie = new Trie();
trie->addWord("algo");
trie->addWord("ala");
trie->addWord("abeja");
trie->addWord("abel");
trie->addWord("trie");
if ( trie->searchWord("abel") )
cout << "Encontrado" << endl;
else cout << "No encontrado" << endl;

delete trie;
}

8.11.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

Aplicaciones

/////////////////////// Suffix Array ///////////////


Algunas Aplicaciones
/////////////// Rotacion lexicografica menor ///////////////
scanf(" %s",&s);
tam1=strlen(s);
for(int i=tam1;i<2*tam1;i++){
s[i]=s[i-tam1];
}
n=2*tam1;
s[n++]=~; //cual quiera de estos { | } ~
suff_arr();
char cam[tam1];
for(int i=0;i<n;i++){
if(r[i]<tam1){
printf(" %d\n",r[i]+1); //inicio lexicografica
for(int j=r[i];j<r[i]+tam1;j++)
cam[j-r[i]]=s[j];
//llenar camino
break;
}
}
for(int i=0;i<tam1;i++){
printf(" %c",cam[i]);
//print camino
}
//nota es un poco caro
/////////////////////// palindromo mas grande ///////////////
usar Manachaer
/////////////////////// mayor substring 2 cadenas ///////////////
n,m tamanio respectivo de las cadenas 1,2 respectivamente
int owner(int idx){
return (idx < n-m-1) ? 1 : 2;
}

71

CAPTULO 8. CADENAS
33
34
35
36
37
38
39
40
41
42
43
44
45

//main
for(int i=0;i<n;i++){
if(owner(r[i]) != owner(r[i-1])){
//por si quiere mostrat $ o #
ans=max(ans,h[i-1]);
// ans subcadena maxima
}
}
//end main
/////////////////////// subcadenas distintas ///////////////
int dev=s.size()*(s.size()+1)/2;
s += $;
suff_arr();lcp();
for(int i=0;i<n;i++)dev-=h[i];
/////////////////////// FIN SUFFIX ARRAY
///////////////

72

Captulo 9

Geometria Computacional
9.1.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
#define MAXC 2501
struct Rect{
int x1,y1, x2,y2;
int color;
int area;
Rect(int _x1, int _y1, int _x2, int _y2){
x1 = _x1;
y1 = _y1;
x2 = _x2;
y2 = _y2;
getArea();
}
int getArea(){
if(x1>=x2 || y1>=y2)return area = 0;
return area = (x2-x1)*(y2-y1);
}
};
Rect interseccion(Rect t, Rect r){
int x1,y1,x2,y2;
x1 = max(t.x1,r.x1);
y1 = max(t.y1,r.y1);
x2 = min(t.x2,r.x2);
y2 = min(t.y2,r.y2);
Rect res(x1,y1,x2,y2);
return res;
}

9.2.
1
2
3

Interseccin de rectangulos

Distancia Punto - Segmento

struct point{
double x,y;
};
73

CAPTULO 9. GEOMETRIA COMPUTACIONAL


4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

inline double dist(const point &a, const point &b){


return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
inline double distsqr(const point &a, const point &b){
return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
}
double distance_point_to_segment(const point &a, const point &b, const point &
pnt){
double u = ((pnt.x - a.x)*(b.x - a.x) + (pnt.y - a.y)*(b.y - a.y)) / distsqr
(a, b);
point intersection;
intersection.x = a.x + u*(b.x - a.x);
intersection.y = a.y + u*(b.y - a.y);
if (u < 0.0 || u > 1.0)
return min(dist(a, pnt), dist(b, pnt));
return dist(pnt, intersection);
}

9.3.
1
2
3
4
5
6
7

74

Distancia Punto - Recta

double distance_point_to_line(const point &a, const point &b, const point &pnt){
double u = ((pnt.x - a.x)*(b.x - a.x) + (pnt.y - a.y)*(b.y - a.y)) / distsqr
(a, b);
point intersection;
intersection.x = a.x + u*(b.x - a.x);
intersection.y = a.y + u*(b.y - a.y);
return dist(pnt, intersection);
}

Captulo 10

Utilitarios
10.1.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

Plantilla

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define

<algorithm>
<iostream>
<iterator>
<cassert>
<sstream>
<fstream>
<cstdlib>
<cstring>
<utility>
<complex>
<string>
<cctype>
<cstdio>
<vector>
<bitset>
<stack>
<queue>
<cmath>
<deque>
<list>
<set>
<map>
ll long long
lld long long int
sc scanf
pf printf
pi 2*acos(0.0)
f first
s second
sz size()
mp make_pair
r(input) freopen("2966.in","r",stdin)
w(output) freopen("output.txt","w",stdout)
maxall(v) *max_element(v.begin(),v.end())
minall(v) *min_element(v.begin(),v.end())
Sort(v) sort(v.begin(),v.end())
un(v) Sort(v), v.erase(unique(v.begin(),v.end()),v.end())
clr(a) memset(a,0,sizeof(a))
pb push_back
lim 100000
75

CAPTULO 10. UTILITARIOS

10.2.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

Lectura rapida

#include <cstdio>
using namespace std;
char line[400000];//OJO maximo mas 3 para el \n y el \0
int now = 0;
inline int getInt(){
int n;
while(1)
if(line[now]!=0){
if(line[now]<0 || line[now]>9){
now++;
continue;
}
n = 0;
while(line[now]>=0 && line[now]<=9) {
n = n*10 + line[now] - 0;
now++;
}
return n;
}
else{
gets(line);
now = 0;
}
return n;
}

10.3.

Espicificadores de formato para printf y scanf

Especificador
%c
%s
%d, %i
%u
%ld
%lu
%lld
%llu
%e, %f, %g
%lf
%o
%x
%patron

10.4.

Tipo
char
cadena
int
unsigned int
long int
unsigned long int
long long int
unsigned long long int
float
double
nmero octal
nmero hexadecimal
patron

Contar bits en 1 en un numero

C++ :
1
2

__builtin_popcount(unsigned int)
__builtin_popcountll(unsigned long long)

76

CAPTULO 10. UTILITARIOS

77

Java :
1

Integer.bitCount(int)

10.5.

Busqueda binaria

C++s Standard Template Library has four functions for binary search, depending on what information you want to
get. They all need
#include <algorithm>
The lower_bound() function returns an iterator to the first position where a value could be inserted without violating the
order; i.e. the first element equal to the element you want, or the place where it would be inserted.
int *ptr = std::lower_bound(array, array+len, what);
// a custom comparator can be given as fourth arg
The upper_bound() function returns an iterator to the last position where a value could be inserted without violating the
order; i.e. one past the last element equal to the element you want, or the place where it would be inserted.
int *ptr = std::upper_bound(array, array+len, what);
// a custom comparator can be given as fourth arg
The equal_range() function returns a pair of the results of lower_bound() and upper_bound().

std::pair<int *, int *> bounds = std::equal_range(array, array+len, what);


// a custom comparator can be given as fourth arg
Note that the difference between the bounds is the number of elements equal to the element you want.
The binary_search() function returns true or false for whether an element equal to the one you want exists in the
array. It does not give you any information as to where it is.
bool found = std::binary_search(array, array+len, what);
// a custom comparator can be given as fourth arg

Anda mungkin juga menyukai