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:
, a distância do
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 , onde
é a mediana. Para que a média seja igual a mediana precisamos é necessário que
. Logo podemos abrir a conta e chegar na conclusão apresentada acima.
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 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:
, onde
representa a soma dos valores de todas as outra variáveis, ou seja, das variáveis conhecidas, e
é 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 é . 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 de vértices tais que não existem dois vértices
e
tais que
,
e
e
são ligados por uma aresta.
Para resolver o problema, vamos iterar por cada bitmask de vértices, desde
até
; 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
é 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 , a bitmask
. O
-ésimo bit
de
terá valor
se
e
são ligados por uma aresta; caso contrário, o
-ésimo bit terá valor
.
Agora, para cada conjunto (ou bitmask) de vértices, defina a bitmask
como o or binário das máscaras
de cada vértice presente em
. Em outras palavras, se
são os índices dos bits com valor
em
, a máscara
será igual a
. Ou seja, pela definição de
,
possuirá o
-ésimo bit igual a
se e somente se houver algum vértice
tal que
e
são ligados por uma aresta.
Portanto, para checar se é um conjunto válido, basta checarmos se
e
possuem bits ligados em comum; se sim, existem dois vértices em
ligados por uma aresta. Caso contrário,
é um conjunto válido. Para checar se
e
possuem bits ligados em comum, basta checar se
.
Como iteramos por todas as possíveis máscaras de bits e calculamos
em
para cada máscara, a complexidade da solução é
. 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 demarcado em um círculo é um retângulo se e somente se as diagonais
e
são diâmetros do círculo.
Com esta observação, basta sabermos se existem quatro pontos no círculo tais que os segmentos
e
são diâmetros, ou seja, a soma dos arcos de
a
e a soma dos arcos de
a
ambas valem metade da circunferência do círculo.
Defina como a soma dos arcos entre os pontos
e
, ou seja,
. Além disso, defina
como o ponto
tal que o segmento
é um diâmetro, ou
caso não exista. Vamos computar, para cada ponto
, o seu valor
. Pela definição de diâmetro, teremos que
é um diâmetro se e somente se
vale metade da circunferência, ou seja,
. Portanto, para encontrar o ponto
(se existir), podemos utilizar uma busca binária no intervalo
. Para calcularmos os valores
de forma eficiente, basta precalcularmos a soma de prefixo do vetor
; assim, se
é a soma do
-ésimo prefixo, conseguimos calcular
em
, já que
.
Após computarmos os valores , resta apenas checar se existem dois pontos
e
tais que
e
. Se sim, existe um retângulo demarcado no círculo formado por
e
. Senão, não existe retângulo algum.
Já que realizamos uma busca binária para cada um dos pontos, a complexidade da solução é
. Confira o código abaixo para melhor entendimento:
PS.: Existe uma solução com complexidade , utilizando a técnica de Two Pointers para encontrar os valores
. Como exercício, tente implementar esta solução!