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 flujoEntrada =
  9.  
  10. private final byte[] buffer = new byte[1 << 16];
  11. private int indice = 0;
  12. private int limite = 0;
  13.  
  14. private int leer() throws IOException {
  15. if (indice >= limite) {
  16. limite = flujoEntrada.read(buffer);
  17. indice = 0;
  18.  
  19. if (limite <= 0) return -1;
  20. }
  21.  
  22. return buffer[indice++];
  23. }
  24.  
  25. int leerEntero() throws IOException {
  26. int simbolo;
  27.  
  28. do {
  29. simbolo = leer();
  30. if (simbolo == -1) return -1;
  31. } while (simbolo <= 32);
  32.  
  33. int numero = 0;
  34.  
  35. while (simbolo > 32) {
  36. numero = numero * 10 + simbolo - '0';
  37. simbolo = leer();
  38. }
  39.  
  40. return numero;
  41. }
  42.  
  43. String leerCadena() throws IOException {
  44. StringBuilder cadenaLeida = new StringBuilder();
  45. int simbolo;
  46.  
  47. do {
  48. simbolo = leer();
  49. if (simbolo == -1) return null;
  50. } while (simbolo <= 32);
  51.  
  52. while (simbolo > 32) {
  53. cadenaLeida.append((char) simbolo);
  54. simbolo = leer();
  55. }
  56.  
  57. return cadenaLeida.toString();
  58. }
  59. }
  60.  
  61. static int[] ordenarSufijos(int[] secuencia) {
  62. int tamano = secuencia.length;
  63.  
  64. int[] sufijos = new int[tamano];
  65. int[] clases = new int[tamano];
  66. int[] auxiliar = new int[tamano];
  67. int[] clasesNuevas = new int[tamano];
  68. int[] frecuencias = new int[Math.max(tamano, 28)];
  69.  
  70. for (int simbolo : secuencia) {
  71. frecuencias[simbolo]++;
  72. }
  73.  
  74. for (int i = 1; i < 28; i++) {
  75. frecuencias[i] += frecuencias[i - 1];
  76. }
  77.  
  78. for (int i = tamano - 1; i >= 0; i--) {
  79. sufijos[--frecuencias[secuencia[i]]] = i;
  80. }
  81.  
  82. int totalClases = 1;
  83. clases[sufijos[0]] = 0;
  84.  
  85. for (int i = 1; i < tamano; i++) {
  86. if (secuencia[sufijos[i]] != secuencia[sufijos[i - 1]]) {
  87. totalClases++;
  88. }
  89.  
  90. clases[sufijos[i]] = totalClases - 1;
  91. }
  92.  
  93. for (int distancia = 1; distancia < tamano; distancia <<= 1) {
  94.  
  95. for (int i = 0; i < tamano; i++) {
  96. auxiliar[i] = sufijos[i] - distancia;
  97.  
  98. if (auxiliar[i] < 0) {
  99. auxiliar[i] += tamano;
  100. }
  101. }
  102.  
  103. Arrays.fill(frecuencias, 0, totalClases, 0);
  104.  
  105. for (int i = 0; i < tamano; i++) {
  106. frecuencias[clases[auxiliar[i]]]++;
  107. }
  108.  
  109. for (int i = 1; i < totalClases; i++) {
  110. frecuencias[i] += frecuencias[i - 1];
  111. }
  112.  
  113. for (int i = tamano - 1; i >= 0; i--) {
  114. int indice = auxiliar[i];
  115. int claseActual = clases[indice];
  116.  
  117. sufijos[--frecuencias[claseActual]] = indice;
  118. }
  119.  
  120. clasesNuevas[sufijos[0]] = 0;
  121.  
  122. int nuevasClases = 1;
  123.  
  124. for (int i = 1; i < tamano; i++) {
  125. int sufijoActual = sufijos[i];
  126. int sufijoAnterior = sufijos[i - 1];
  127.  
  128. int segundaParteActual =
  129. (sufijoActual + distancia) % tamano;
  130.  
  131. int segundaParteAnterior =
  132. (sufijoAnterior + distancia) % tamano;
  133.  
  134. if (clases[sufijoActual] != clases[sufijoAnterior] ||
  135. clases[segundaParteActual] !=
  136. clases[segundaParteAnterior]) {
  137.  
  138. nuevasClases++;
  139. }
  140.  
  141. clasesNuevas[sufijoActual] = nuevasClases - 1;
  142. }
  143.  
  144. int[] intercambio = clases;
  145. clases = clasesNuevas;
  146. clasesNuevas = intercambio;
  147.  
  148. totalClases = nuevasClases;
  149.  
  150. if (totalClases == tamano) {
  151. break;
  152. }
  153. }
  154.  
  155. return sufijos;
  156. }
  157.  
  158. static int[] calcularLcp(int[] secuencia, int[] sufijos) {
  159. int tamano = secuencia.length;
  160.  
  161. int[] rangoSufijos = new int[tamano];
  162. int[] prefijosComunes = new int[tamano];
  163.  
  164. for (int i = 0; i < tamano; i++) {
  165. rangoSufijos[sufijos[i]] = i;
  166. }
  167.  
  168. int longitudCompartida = 0;
  169.  
  170. for (int i = 0; i < tamano; i++) {
  171. int rangoActual = rangoSufijos[i];
  172.  
  173. if (rangoActual == 0) {
  174. longitudCompartida = 0;
  175. continue;
  176. }
  177.  
  178. int sufijoAnterior = sufijos[rangoActual - 1];
  179.  
  180. while (i + longitudCompartida < tamano &&
  181. sufijoAnterior + longitudCompartida < tamano &&
  182. secuencia[i + longitudCompartida] ==
  183. secuencia[sufijoAnterior + longitudCompartida]) {
  184.  
  185. longitudCompartida++;
  186. }
  187.  
  188. prefijosComunes[rangoActual] = longitudCompartida;
  189.  
  190. if (longitudCompartida > 0) {
  191. longitudCompartida--;
  192. }
  193. }
  194.  
  195. return prefijosComunes;
  196. }
  197.  
  198. static int[] construirTexto(
  199. String primeraCadena,
  200. String segundaCadena,
  201. int tamanoCadena
  202. ) {
  203. int[] secuencia = new int[4 * tamanoCadena + 2];
  204.  
  205. int inicioSegunda = 2 * tamanoCadena + 1;
  206.  
  207. for (int indice = 0; indice < tamanoCadena; indice++) {
  208. int codigoPrimera =
  209. primeraCadena.charAt(indice) - 'a' + 2;
  210.  
  211. int codigoSegunda =
  212. segundaCadena.charAt(indice) - 'a' + 2;
  213.  
  214. secuencia[indice] = codigoPrimera;
  215. secuencia[indice + tamanoCadena] = codigoPrimera;
  216.  
  217. secuencia[inicioSegunda + indice] = codigoSegunda;
  218. secuencia[inicioSegunda + tamanoCadena + indice] =
  219. codigoSegunda;
  220. }
  221.  
  222. secuencia[2 * tamanoCadena] = 1;
  223. secuencia[4 * tamanoCadena + 1] = 0;
  224.  
  225. return secuencia;
  226. }
  227.  
  228. static long contarPares(
  229. int tamanoCadena,
  230. int[] sufijos,
  231. int[] prefijosComunes
  232. ) {
  233. int inicioSegunda = 2 * tamanoCadena + 1;
  234. int ultimoValido = -1;
  235.  
  236. int primeraCantidad = 0;
  237. int segundaCantidad = 0;
  238.  
  239. int minimoCompartido = Integer.MAX_VALUE;
  240.  
  241. long primeraAcumulada = 0;
  242. long totalPares = 0;
  243.  
  244. for (int indice = 0; indice < sufijos.length; indice++) {
  245.  
  246. if (ultimoValido != -1 && indice > ultimoValido) {
  247. minimoCompartido = Math.min(
  248. minimoCompartido,
  249. prefijosComunes[indice]
  250. );
  251. }
  252.  
  253. int sufijo = sufijos[indice];
  254.  
  255. boolean esPrimera = sufijo < tamanoCadena;
  256.  
  257. boolean esSegunda =
  258. sufijo >= inicioSegunda &&
  259. sufijo < inicioSegunda + tamanoCadena;
  260.  
  261. if (!esPrimera && !esSegunda) {
  262. continue;
  263. }
  264.  
  265. if (ultimoValido == -1 || minimoCompartido < tamanoCadena) {
  266.  
  267. totalPares += primeraAcumulada * segundaCantidad;
  268.  
  269. totalPares +=
  270. (long) primeraCantidad * segundaCantidad;
  271.  
  272. primeraAcumulada += primeraCantidad;
  273.  
  274. primeraCantidad = 0;
  275. segundaCantidad = 0;
  276. }
  277.  
  278. if (esPrimera) {
  279. primeraCantidad++;
  280. } else {
  281. segundaCantidad++;
  282. }
  283.  
  284. ultimoValido = indice;
  285. minimoCompartido = Integer.MAX_VALUE;
  286. }
  287.  
  288. totalPares += primeraAcumulada * segundaCantidad;
  289.  
  290. totalPares +=
  291. (long) primeraCantidad * segundaCantidad;
  292.  
  293. return totalPares;
  294. }
  295.  
  296. static long resolver(
  297. int tamanoCadena,
  298. String primeraCadena,
  299. String segundaCadena
  300. ) {
  301. int[] secuencia = construirTexto(
  302. primeraCadena,
  303. segundaCadena,
  304. tamanoCadena
  305. );
  306.  
  307. int[] sufijos = ordenarSufijos(secuencia);
  308.  
  309. int[] prefijosComunes = calcularLcp(secuencia, sufijos);
  310.  
  311. return contarPares(
  312. tamanoCadena,
  313. sufijos,
  314. prefijosComunes
  315. );
  316. }
  317.  
  318. public static void main(String[] args) throws IOException {
  319.  
  320. EntradaRapida lector = new EntradaRapida();
  321.  
  322. int tamanoCadena = lector.leerEntero();
  323.  
  324. if (tamanoCadena == -1) return;
  325.  
  326. String primeraCadena = lector.leerCadena();
  327. String segundaCadena = lector.leerCadena();
  328.  
  329. System.out.println(
  330. resolver(tamanoCadena, primeraCadena, segundaCadena)
  331. );
  332. }
  333. }
  334.  
Success #stdin #stdout 0.07s 52768KB
stdin
Standard input is empty
stdout
Standard output is empty