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!