fork download
  1.  
  2. import java.io.*;
  3. import java.util.*;
  4.  
  5. public class Main {
  6.  
  7. static class EntradaRapida {
  8. private final BufferedInputStream entrada =
  9.  
  10. private final byte[] datos = new byte[1 << 16];
  11. private int pos = 0;
  12. private int longitud = 0;
  13.  
  14. private int leer() throws IOException {
  15. if (pos >= longitud) {
  16. longitud = entrada.read(datos);
  17. pos = 0;
  18.  
  19. if (longitud <= 0) return -1;
  20. }
  21.  
  22. return datos[pos++];
  23. }
  24.  
  25. String leerCadena() throws IOException {
  26. StringBuilder texto = new StringBuilder();
  27. int caracter;
  28.  
  29. do {
  30. caracter = leer();
  31. if (caracter == -1) return null;
  32. } while (caracter <= 32);
  33.  
  34. while (caracter > 32) {
  35. texto.append((char) caracter);
  36. caracter = leer();
  37. }
  38.  
  39. return texto.toString();
  40. }
  41.  
  42. int leerEntero() throws IOException {
  43. int caracter;
  44.  
  45. do {
  46. caracter = leer();
  47. if (caracter == -1) return -1;
  48. } while (caracter <= 32);
  49.  
  50. int valor = 0;
  51.  
  52. while (caracter > 32) {
  53. valor = valor * 10 + caracter - '0';
  54. caracter = leer();
  55. }
  56.  
  57. return valor;
  58. }
  59. }
  60.  
  61. static int[] construirSufijos(int[] texto) {
  62. int n = texto.length;
  63.  
  64. int[] orden = new int[n];
  65. int[] clase = new int[n];
  66. int[] desplazados = new int[n];
  67. int[] nuevaClase = new int[n];
  68. int[] conteo = new int[Math.max(n, 28)];
  69.  
  70. for (int valor : texto) {
  71. conteo[valor]++;
  72. }
  73.  
  74. for (int i = 1; i < 28; i++) {
  75. conteo[i] += conteo[i - 1];
  76. }
  77.  
  78. for (int i = n - 1; i >= 0; i--) {
  79. orden[--conteo[texto[i]]] = i;
  80. }
  81.  
  82. int clases = 1;
  83. clase[orden[0]] = 0;
  84.  
  85. for (int i = 1; i < n; i++) {
  86. if (texto[orden[i]] != texto[orden[i - 1]]) {
  87. clases++;
  88. }
  89.  
  90. clase[orden[i]] = clases - 1;
  91. }
  92.  
  93. for (int salto = 1; salto < n; salto <<= 1) {
  94.  
  95. for (int i = 0; i < n; i++) {
  96. desplazados[i] = orden[i] - salto;
  97.  
  98. if (desplazados[i] < 0) {
  99. desplazados[i] += n;
  100. }
  101. }
  102.  
  103. Arrays.fill(conteo, 0, clases, 0);
  104.  
  105. for (int i = 0; i < n; i++) {
  106. conteo[clase[desplazados[i]]]++;
  107. }
  108.  
  109. for (int i = 1; i < clases; i++) {
  110. conteo[i] += conteo[i - 1];
  111. }
  112.  
  113. for (int i = n - 1; i >= 0; i--) {
  114. int actual = desplazados[i];
  115. int grupo = clase[actual];
  116.  
  117. orden[--conteo[grupo]] = actual;
  118. }
  119.  
  120. nuevaClase[orden[0]] = 0;
  121.  
  122. int nuevasClases = 1;
  123.  
  124. for (int i = 1; i < n; i++) {
  125. int actual = orden[i];
  126. int anterior = orden[i - 1];
  127.  
  128. int medioActual = (actual + salto) % n;
  129. int medioAnterior = (anterior + salto) % n;
  130.  
  131. if (clase[actual] != clase[anterior] ||
  132. clase[medioActual] != clase[medioAnterior]) {
  133.  
  134. nuevasClases++;
  135. }
  136.  
  137. nuevaClase[actual] = nuevasClases - 1;
  138. }
  139.  
  140. int[] temporal = clase;
  141. clase = nuevaClase;
  142. nuevaClase = temporal;
  143.  
  144. clases = nuevasClases;
  145.  
  146. if (clases == n) break;
  147. }
  148.  
  149. return orden;
  150. }
  151.  
  152. static int[] calcularLcp(int[] texto, int[] orden) {
  153. int n = texto.length;
  154.  
  155. int[] rango = new int[n];
  156. int[] lcp = new int[n];
  157.  
  158. for (int i = 0; i < n; i++) {
  159. rango[orden[i]] = i;
  160. }
  161.  
  162. int comun = 0;
  163.  
  164. for (int i = 0; i < n; i++) {
  165. int posicion = rango[i];
  166.  
  167. if (posicion == 0) {
  168. comun = 0;
  169. continue;
  170. }
  171.  
  172. int anterior = orden[posicion - 1];
  173.  
  174. while (i + comun < n &&
  175. anterior + comun < n &&
  176. texto[i + comun] == texto[anterior + comun]) {
  177.  
  178. comun++;
  179. }
  180.  
  181. lcp[posicion] = comun;
  182.  
  183. if (comun > 0) {
  184. comun--;
  185. }
  186. }
  187.  
  188. return lcp;
  189. }
  190.  
  191. static long resolver(int n, String cadenaS, String cadenaT) {
  192.  
  193. int total = 4 * n + 2;
  194. int inicioT = 2 * n + 1;
  195.  
  196. int[] texto = new int[total];
  197.  
  198. for (int i = 0; i < n; i++) {
  199. int letraS = cadenaS.charAt(i) - 'a' + 2;
  200. int letraT = cadenaT.charAt(i) - 'a' + 2;
  201.  
  202. texto[i] = letraS;
  203. texto[i + n] = letraS;
  204.  
  205. texto[inicioT + i] = letraT;
  206. texto[inicioT + n + i] = letraT;
  207. }
  208.  
  209. texto[2 * n] = 1;
  210. texto[total - 1] = 0;
  211.  
  212. int[] orden = construirSufijos(texto);
  213. int[] lcp = calcularLcp(texto, orden);
  214.  
  215. long respuesta = 0;
  216. long vistosS = 0;
  217.  
  218. int cantidadS = 0;
  219. int cantidadT = 0;
  220.  
  221. int anteriorValido = -1;
  222. int minimoComun = Integer.MAX_VALUE;
  223.  
  224. for (int i = 0; i < total; i++) {
  225.  
  226. if (anteriorValido != -1 && i > anteriorValido) {
  227. minimoComun = Math.min(minimoComun, lcp[i]);
  228. }
  229.  
  230. int posicion = orden[i];
  231.  
  232. boolean esS = posicion < n;
  233.  
  234. boolean esT = posicion >= inicioT &&
  235. posicion < inicioT + n;
  236.  
  237. if (!esS && !esT) {
  238. continue;
  239. }
  240.  
  241. if (anteriorValido == -1 || minimoComun < n) {
  242.  
  243. if (anteriorValido != -1) {
  244. respuesta += vistosS * cantidadT +
  245. (long) cantidadS * cantidadT;
  246.  
  247. vistosS += cantidadS;
  248. }
  249.  
  250. cantidadS = 0;
  251. cantidadT = 0;
  252. }
  253.  
  254. if (esS) {
  255. cantidadS++;
  256. } else {
  257. cantidadT++;
  258. }
  259.  
  260. anteriorValido = i;
  261. minimoComun = Integer.MAX_VALUE;
  262. }
  263.  
  264. respuesta += vistosS * cantidadT +
  265. (long) cantidadS * cantidadT;
  266.  
  267. return respuesta;
  268. }
  269.  
  270. public static void main(String[] args) throws IOException {
  271.  
  272. EntradaRapida lector = new EntradaRapida();
  273.  
  274. int n = lector.leerEntero();
  275.  
  276. if (n == -1) return;
  277.  
  278. String cadenaS = lector.leerCadena();
  279. String cadenaT = lector.leerCadena();
  280.  
  281. System.out.println(resolver(n, cadenaS, cadenaT));
  282. }
  283. }
Success #stdin #stdout 0.07s 54816KB
stdin
Standard input is empty
stdout
Standard output is empty