OBI 2021 – Fase 2 Turno A – Programação Nível 2
Para se preparar para a OBI, confira o nosso Roteiro de Estudos, nele você vai encontrar um direcionamento completo de como estudar!
Comentário escrito por Thiago Mota, Leonardo Paes e Lúcio Figueiredo
Para conferir a prova na íntegra, clique aqui.
Média e Mediana
Conhecimento prévio necessário:
Para que a média seja igual a mediana, basta que a distância do elemento do meio para as pontas seja a mesma, por exemplo: $$2$$ $$5$$ $$7$$, a distância do $$5$$ para as pontas é a mesma, logo a média e a mediana ficam no mesmo ponto. Podemos demonstrar isso matematicamente:
Pegue 3 números em ordem não-decrescente $$a, b, c$$, onde $$b$$ é a mediana. Para que a média seja igual a mediana precisamos é necessário que $$\frac{a+b+c}{3} = b$$. Logo podemos abrir a conta e chegar na conclusão apresentada acima.
$$ \frac{a+b+c}{3} = b $$
$$ a+b+c = 3b $$
$$ ac = 2b $$
$$ c-b = b-a $$
Para resolver o problema, basta escolher qualquer número de tal forma que a diferença entre o maior e o menor seja igual o do meio. Segue o código:
Passatempo
Conhecimento prévio necessário:
Esse é um problema de simulação. O enunciado nos garante que sempre haverá um valor possível de ser descoberto. Portanto, o problema se resume em implementar cautelosamente um algoritmo que sempre encontrará pelo menos o valor de uma variável que ainda não havia sido descoberto. Uma maneira de se fazer isso é mantendo um $$set<string,int>$$ que guardará, para cada variável, o seu valor. Assim, simularemos o seguinte algoritmo até termos encontrado todas as variáveis:
- Itere por cada linha e coluna da matriz. Se em nenhuma das linhas e colunas há exatamente uma variável de valor desconhecido, termine o algoritmo. Senão, realize a etapa seguinte nesta linha/coluna;
- Para descobrirmos o valor da variável desconhecida nesta linha/coluna, utilizarmos a seguinte equação: $$valor = \frac{(soma_{(linha/coluna)} – soma_{(conhecida)})}{quantidade}$$, onde $$soma_{(conhecida)}$$ representa a soma dos valores de todas as outra variáveis, ou seja, das variáveis conhecidas, e $$quantidade$$ é a quantidade de vezes que a variável cujo valor ainda é desconhecido aparece na respectiva linha/coluna.
- Armazene o valor encontrado no set e repita o passo 1.
Como utilizamos um set em cada iteração do algoritmo, a complexidade da solução é $$O(N \cdot M \cdot \log_{} N)$$. Confira o código a seguir para melhor entendimento:
Sanduíche
Conhecimento prévio necessário:
Se interpretarmos cada ingrediente como um vértice de um grafo e cada par de ingredientes que não combinam como uma aresta, o problema se resume a encontrar a quantidade de subconjuntos $$S$$ de vértices tais que não existem dois vértices $$u$$ e $$v$$ tais que $$u \in S$$, $$v \in S$$ e $$u$$ e $$v$$ são ligados por uma aresta.
Para resolver o problema, vamos iterar por cada bitmask $$S$$ de vértices, desde $$1$$ até $$2^N – 1$$; assim, cada bitmask representa um conjunto de vértices, de modo que um bit aceso na máscara representa um vértice pertencente ao conjunto. Para saber se $$S$$ é um conjunto válido, resta checarmos se existem dois vértices presentes no conjunto ligados por uma aresta.
Para checar esta condição, vamos precalcular, para cada vértice $$u$$, a bitmask $$bad[u]$$. O $$v$$-ésimo bit $$(0 \leq v \leq N-1)$$ de $$bad[u]$$ terá valor $$1$$ se $$u$$ e $$v$$ são ligados por uma aresta; caso contrário, o $$v$$-ésimo bit terá valor $$0$$.
Agora, para cada conjunto (ou bitmask) $$S$$ de vértices, defina a bitmask $$aux$$ como o or binário das máscaras $$bad[]$$ de cada vértice presente em $$S$$. Em outras palavras, se $$i_1, i_2, …, i_k$$ são os índices dos bits com valor $$1$$ em $$S$$, a máscara $$aux$$ será igual a $$bad[i_1] \ | \ bad[i_2] \ | \ … \ | \ bad[i_k]$$. Ou seja, pela definição de $$bad[]$$, $$aux$$ possuirá o $$i$$-ésimo bit igual a $$1$$ se e somente se houver algum vértice $$j \in S$$ tal que $$i$$ e $$j$$ são ligados por uma aresta.
Portanto, para checar se $$S$$ é um conjunto válido, basta checarmos se $$aux$$ e $$S$$ possuem bits ligados em comum; se sim, existem dois vértices em $$S$$ ligados por uma aresta. Caso contrário, $$S$$ é um conjunto válido. Para checar se $$aux$$ e $$S$$ possuem bits ligados em comum, basta checar se $$(S \ \& \ aux) \neq 0$$.
Como iteramos por todas as $$2^n$$ possíveis máscaras de bits e calculamos $$aux$$ em $$O(N)$$ para cada máscara, a complexidade da solução é $$O(2^N \cdot N)$$. Confira o código abaixo para melhor entendimento:
Retângulo
Conhecimento prévio necessário:
Para resolver o problema, vamos utilizar a seguinte observação:
Observação: Um quadrilátero $$ABCD$$ demarcado em um círculo é um retângulo se e somente se as diagonais $$AC$$ e $$BD$$ são diâmetros do círculo.
Com esta observação, basta sabermos se existem quatro pontos $$A < B < C < D$$ no círculo tais que os segmentos $$AC$$ e $$BD$$ são diâmetros, ou seja, a soma dos arcos de $$A$$ a $$C$$ e a soma dos arcos de $$B$$ a $$D$$ ambas valem metade da circunferência do círculo.
Defina $$S(i, j)$$ como a soma dos arcos entre os pontos $$i$$ e $$j$$ $$(i < j)$$, ou seja, $$L_{i+1} + L_{i+2} + … + L_j$$. Além disso, defina $$D(i)$$ como o ponto $$j$$ tal que o segmento $$ij$$ é um diâmetro, ou $$-1$$ caso não exista. Vamos computar, para cada ponto $$i$$, o seu valor $$D(i)$$. Pela definição de diâmetro, teremos que $$ij$$ é um diâmetro se e somente se $$S(i, j)$$ vale metade da circunferência, ou seja, $$\frac{S(0, n)}{2}$$. Portanto, para encontrar o ponto $$j$$ (se existir), podemos utilizar uma busca binária no intervalo $$[i+1, n]$$. Para calcularmos os valores $$S(i, j)$$ de forma eficiente, basta precalcularmos a soma de prefixo do vetor $$L$$; assim, se $$P_x$$ é a soma do $$x$$-ésimo prefixo, conseguimos calcular $$S(i, j)$$ em $$O(1)$$, já que $$S(i, j) = P_{j} – P_{i-1}$$.
Após computarmos os valores $$D(i)$$, resta apenas checar se existem dois pontos $$A$$ e $$B$$ tais que $$D(A) \neq -1$$ e $$D(B) \neq -1$$. Se sim, existe um retângulo demarcado no círculo formado por $$A, B, D(A)$$ e $$D(B)$$. Senão, não existe retângulo algum.
Já que realizamos uma busca binária para cada um dos $$N$$ pontos, a complexidade da solução é $$O(N \cdot \log_{} N)$$. Confira o código abaixo para melhor entendimento:
PS.: Existe uma solução com complexidade $$O(N)$$, utilizando a técnica de Two Pointers para encontrar os valores $$D(i)$$. Como exercício, tente implementar esta solução!
