Editorial for Contando subarreglos
Submitting an official solution before solving the problem yourself is a bannable offence.
Author:
Primera subtarea: Fijar i, y hacer un ciclo a partir de i manteniendo el OR y el maximo, y en cada iteracion si OR > max contar 1.
Segunda subtarea: La primera observacion es que, max( l , r ) >= max ( l , r - 1 ) y max( l , r ) >= max( l + 1 , r ) para todo l < r. Ademas OR( l , r ) >= OR( l , r - 1 ) y OR( l , r ) >= OR( l + 1 , r ) para todo l < r. Una posible observacion es que podemos contar los subarreglos en los que el OR es igual al maximo, y restarselo al total de subarreglos que es n(n-1)/2.
Solucion con Divide and Conquer: Primero que todo, preparamos una estructura de datos que nos permita conocer el OR o el maximo de un subarreglo en O(1) por query, dicha estructura es un sparse table del arreglo. Ahora tenemos una funcion f(l,r) que nos cuenta la cantidad de subarreglos en los cuales el OR es mayor que el maximo, para resolver f(l,r) hacemos lo siguiente: Buscamos el maximo de l a r, digamos que es max, y su posicion es pmax. Si ( pmax - l ) <= ( r - pmax ) recorremos el rango de l a pmax, y para cada posicion hacemos una busqueda binaria para buscar la posicion mas a la izquierda en la cual el OR es mayor que el maximo(max), apoyandonos en las querys que podemos hacer en el sparse table en O(1), digamos que esta posicion es optr, entonces sumamos ( r - max(optr,pmax) + 1 ) a la solucion. Si ( pmax - l ) > ( r - pmax ) recorremos el rango de pmax a r, y para cada posicion hacemos una busqueda binaria para buscar la posicion mas a la derecha en la cual el OR es mayor que el maximo(max), apoyandonos en las querys que podemos hacer en el sparse table en O(1), digamos que esta posicion es optl, entonces sumamos min(optl,pmax) a la solucion. Note que aqui calculamos todos los tramos donde a[pmax] es el maximo, luego de esto sumamos f(l,pmax-1) y f(pmax+1,r), recursivamente. En total solo haremos nlogn busquedas binarias, debido a que se hacen en total n llamadas a la funcion(cada llamada elimina a un elemento), y para si en una llamada recorremos x posiciones, partimos el array en uno de tamagno x y otro de n - x, por lo cual, si recorremos algun x considerablemente grande, el tamagno del arreglo sera reducido considerablemente, para mas precision se puede calcular la complejidad del peor caso, definamoslo como C(m), entonces C(m) es igual al maximo para cada i entre 1 y n de C(i-1) + C(n-i) + min( i - 1 , n - i ). Esto se puede calcular y se puede ver que es aproximadamente nlogn. Y como cada busqueda binaria es logn la complejidad total es nlog^2n. Esta no es la solucion mas facil a este ejercicio, ni la mas corta, ni la mas rapida, pero esta instructiva y lleva pocas observaciones y se puede aplicar a otros problemas parecidos.
Solucion mas simple: Vamos a ir por cada i entre 1 y n, y contar las soluciones en las que el maximo de ese intervalo es a[i], entonces vamos a buscar la posicion mas a la derecha de 1 a i - 1, llamemosle pl que cumpla que OR(a[pl],a[pl+1],...,a[i]) = a[i], y guardar pl[i] para cada i, note que no es necesario preguntar por el maximo, ya que si el OR es igual a a[i], no puede haber ningun elemento mayor que a[i]. Luego hacemos los mismo por la derecha, buscar la posicion pr mas a la izquierda de i + 1 a n, que el OR sea igual a a[i], y guardar pr[i] para cada i, pero en este caso hay una condicion extra, que max(a[i+1],a[i+2],...,a[pr]) tiene que ser estrictamente menor que a[i], de lo contrario contariamos subarreglos multiples veces si el arreglo tiene numeros repetidos, por ejemplo en 2 2, contariamos 4, y en realidad solo son 3 subarreglos. Luego la cantidad de subarreglos "malos"(que el OR es igual al maximo) es la suma para cada i de ( i - pl[i] + 1 ) * ( pr[i] - i + 1 ). Calculamos esto y se lo restamos al total y ya tenemos la solucion. Ahora veamos como calcular pl[i] y pr[i] para cada i. Una opcion es hacer busqueda binaria y queries de maximo y or en rango, con un segment tree queda nlog^2 y con un sparse table nlogn. Ademas esto se puede hacer en O(n) manteniendo una stack, que lleve el OR y el maximo, y removiendo el tope cuando sea necesario, recuerde que en la parte de la derecha el maximo tiene que ser estrictamente menor que a[i].
Comments