OBI 2021 - Fase 2 Turno B - Programação Nível 1
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 Anita Almeida, Leonardo Paes, Lúcio Figueiredo e Pedro Racchetti
Para conferir a prova na íntegra, clique aqui.
Recorde
Conhecimento prévio necessário:
Este problema é bem simples e utiliza apenas a estrutura condicional . Após ler os valores, basta comparar se é menor que para determinar se é um recorde mundial, e se é menor que para determinar se é um recorde olímpico. Se nenhum dois casos for verdade, basta imprimir .
A complexidade da solução é . Segue o código para melhor compreensão da solução:
Potência
Conhecimento prévio necessário:
- Estruturas Condicionais
- Loops
- Apenas por curiosidade, Congruências
Como dito pelo enunciado do problema, a potência é composta por um único dígito. Então, supomos que estamos lendo um inteiro . Sabemos que na verdade, queremos . Portanto, uma maneira simples de fazer isso é a seguinte: Após lermos o inteiro , utilizaremos a função %, que nos retornará o número módulo , ou seja, o resto na divisão por do número em questão. Note que esse valor sempre será o último dígito do número, ou seja, o dígito das unidades. Valor este que representa a potência do nosso termo. Para eliminarmos o último dígito do número, podemos dividí-lo por 10 e tomar a parte inteira da operação. Em C++, , já que o operador obtém a parte inteira da divisão. Essa operação faz exatamente o que nós precisamos.
A complexidade da solução é . Confira o código abaixo para melhor entendimento:
PS.: Caso deseje ver uma explicação detalhada das operações realizadas acima, confira a solução do problema Cálculo rápido abaixo.
Cálculo rápido
Conhecimento prévio necessário:
Para resolver este problema, precisamos pensar em como podemos calcular a soma dos dígitos de um número de forma eficiente. Ou seja, dado um número , precisamos encontrar cada um dos dígitos de individualmente; feito isso, é fácil calcular a sua soma.
Algortimo para encontrar os dígitos de
Para extraírmos cada um dos dígitos de , podemos utilizar o seguinte algoritmo:
- Encontre o último dígito de ;
- Remova o dígito de . Denote o número resultante por ;
- Se não possuir dígito algum, termine o algoritmo. Senão, repita o passo 1 com o novo número .
Apesar do algoritmo acima estar correto, ainda é necessário descobrir como calcular o último dígito de e como removê-lo.
Encontrar o último dígito de
Seja o quociente e o resto na divisão de por . Com esta definição, temos que . Observe que como é um múltiplo de , o seu último dígito é igual a . Além disso, como é o resto da divisão de por , temos que . Portanto, podemos concluir que o valor é igual ao último dígito de em sua representação decimal! Para observar isto, considere os seguintes exemplos:
: . Último dígito de é igual a .
: . Último dígito de é igual a .
: . Último dígito de é igual a .
Com esta observação, concluímos que o último dígito de é igual a , já que o operador calcula o resto da divisão de um inteiro por outro.
Remover o último dígito de
Como é o último dígito de e , podemos observar que é igual ao valor - ou seja, o valor resultante da remoção do último dígito de . Novamente, considere os seguintes exemplos para melhor entendimento:
: . é igual a .
: . é igual a .
: . é igual a .
Para encontrar o valor , observe que, por definição, ele é igual a . Porém, como , temos que é igual à parte inteira de . Portanto, o valor é igual a , já que o operador calcula a parte inteira da divisão.
Agora que sabemos como executar cada passo do algoritmo apresentado acima, basta o utilizarmos para encontrar a soma dos dígitos de .
Complexidade do algoritmo
Observe que a complexidade do algoritmo acima é proporcional à quantidade de dígitos de . Portanto, como a quantidade de dígitos de é menor ou igual a , a complexidade final do algoritmo é .
Etapa final
Agora que possuímos um algoritmo eficiente para encontrar as somas dos dígitos de um número inteiro, o que sobra para terminarmos o problema é executá-lo para cada inteiro entre e , utilizando um loop For. Caso a soma dos dígitos de seja igual a , adicionamos em uma variável de resposta, e imprimimos o seu valor ao final do código.
Como executamos o algoritmo acima em todos os números entre e , a complexidade final da solução é . Para melhor entendimento, confira o código abaixo:
Lista palíndroma
Conhecimento prévio necessário:
Antes de resolver o problema, podemos fazer algumas observações iniciais. Para uma subarray , com da lista fornecida, note:
- Se , então o número de operações necessárias é ;
- Se , não precisamos fazer uma operação, bastando resolver o problema para a subarray ;
- Se , precisamos aumentar . Dessa forma, precisamos fazer uma operação de contração com o consecutivo de . A mesma ideia se aplica para o caso de , fazendo a operação entre e .
Podemos então usar as observações do algoritmo de Two Pointers indicado no link acima, usando como subarray o intervalo - ou seja, a lista inteira. Usaremos então como o primeiro ponteiro, começando no início da lista, e como segundo ponteiro, começando no fim da lista, até que se encontrem pelas operações acima.
A complexidade final da solução é . Segue o código comentado, para melhor compreensão: