Restaurante
Solução escrita por Theo Sampaio
Conhecimentos necessários:
Esse problema pode ser resolvido usando um algoritmo guloso para agrupar os grupos em mesas de forma ótima.
Deixe que $$ans$$ seja a quantidade de mesas necessárias para agrupar todos os grupos, e as variáveis $$G_1$$ a $$G_4$$ o número de grupos de cada tipo.
Parcial 1 – Todos os grupos são de tamanho 1 ($$G_2$$, $$G_3$$, $$G_4$$ = 0) (20 pontos)
Sabemos que a divisão de um número $$n$$ por outro número $$k$$ representa quantos grupos de tamanho $$k$$ cabem em $$n$$. Logo, $$\frac{G_1}{4}$$ representa o número de mesas necessárias para alocar os clientes, desde que arredondado para cima. Como a divisão no C++ arredonda para baixo, usamos a seguinte identidade:
$$\Large
\left\lceil \frac{n}{k} \right\rceil
=
\left\lfloor \frac{n+k-1}{k} \right\rfloor
$$
E a resposta é, então:
$$(G_1 + 3)/4$$
Parcial 2 – Sem restrições adicionais
É trivial que os grupos de 4 pessoas deverão ocupar mesas inteiras, logo somamos $$G_4$$ a $$ans$$. Além disso, como um grupo não pode ser dividido entre mesas, grupos de 3 pessoas necessariamente ocupam uma mesa também, desde que contabilizemos o número de espaços vazios, que poderão ser usados por grupos de 1 pessoa posteriormente.
Grupos de 2 pessoas, por sua vez, podem ser pareados com grupos de 2 pessoas. Caso o número de grupos de 2 pessoas seja ímpar, teremos uma mesa com 2 lugares sobrando também.
Logo, podemos agrupar os grupos de 1 nas mesas com sobra, e caso ainda tenham grupos de 1 pessoa, alocamo-los em mesas usando o resultado da parcial 1. Para isso, definimos $$K$$ como a quantidade de grupos de 1 pessoa que ainda restam após preencher todos os lugares vagos.
Isso pode ser resumido com as seguintes operações:
$$K = \max\left(0,\:G_1\:-\:G_3\:-\:2*(G_2\:\bmod\:2)\right)$$
$$ans = G_4 + G_3 +\left\lceil \frac{G_2}{2} \right\rceil + \left\lceil \frac{K}{4} \right\rceil$$
Encontro de Amigas
Solução escrita por Márcio Vitor
Conhecimentos necessários:
Subtarefa 2 – ($$A_1 = A_2$$):
Perceba que a resposta é no máximo 1 pois Ana permanecera apenas 1 dia no Brasil, então basta checar se esse dia esta dentro dos outros dois intervalos de tempo, se sim retorne 1, caso contrario retorne 0.
Para verificar se um tempo x esta dentro de um intervalo $$[L,R]$$ basta checar se $$x >= L$$ e $$x <= R$$.
Subtarefa 3 – (sem restrições adicionais):
Usando as ideias da subtarefa 2, vamos manter um contador $$cnt$$, e iremos iterar pelos possíveis dias $$D$$ de 1 a 31 e ver se ele esta dentro de todos os intervalos que as garotas estarão no Brasil, se sim adicionamos 1, ao final de tudo $$cnt$$ será a resposta.
Clique aqui para ver o código completo.
Mercadinho
Solução escrita por Malu Azevedo
O problema nos pede o menor tempo em segundos para que todos os idosos () fiquem no início da fila. A cada segundo, múltiplos idosos podem dar um passo à frente simultaneamente, desde que ultrapassem uma pessoa jovem ().
Ideia Central
A observação crucial para resolver este problema de forma ótima é notar que um idoso nunca é atrasado por outro idoso de modo a gastar segundos adicionais.
Como todos os idosos elegíveis se movem ao mesmo tempo, se houver um bloco de idosos juntos, eles se deslocam para a frente em “bloco” assim que o primeiro idoso desse grupo encontrar e ultrapassar um jovem. Portanto, o tempo que um idoso leva para chegar à sua posição final depende única e exclusivamente da quantidade de jovens que estão inicialmente à sua frente.
Se um idoso possui J jovens à sua esquerda na fila original, ele precisará de exatamente J segundos para ultrapassar todos eles.
Como todos os movimentos ocorrem em paralelo, o tempo total necessário para organizar toda a fila será determinado pelo idoso que estiver na pior situação possível. Logo, a resposta é o máximo de jovens à frente de qualquer idoso. Caso não haja nenhum idoso na fila, a resposta é 0.
Subtarefa 2 – (40 pontos)
Com um limite de pequeno, uma solução que simule o processo segundo por segundo (realizando as trocas no vetor manualmente até que nenhum idoso precise se mover) é aceitável. Uma simulação direta custaria no máximo operações, o que roda tranquilamente dentro do tempo para .
Subtarefa 3 – Existe um único idoso na fila (20 pontos)
Como há apenas um idoso, basta percorrer a fila até encontrá-lo. Todas as pessoas antes dele serão obrigatoriamente jovens. Portanto, a resposta é simplesmente o número de elementos avaliados antes de achar o idoso (o seu índice 0-indexado). Resultando em uma complexidade
Subtarefa 4 – Nenhuma restrição adicional ()(40 pontos)
Para garantir os 100 pontos, precisamos de uma abordagem linear . Utilizando a nossa ideia central, podemos resolver o problema em uma única passada pelo vetor:
Mantemos um contador jovens=0 e uma variável tempomax=0.
Percorremos a fila do início ao fim:
- Se a pessoa atual for jovem, incrementamos
jovens. - Se a pessoa atual for idosa, ela precisará passar por todos os jovens acumulados até ali. Atualizamos
tempomax = max(tempomax, jovens).
Ao final da leitura, tempomax terá a resposta correta.
Clique aqui para ver o código completo.
Torre de Números
Solução escrita por Malu Azevedo
Conhecimentos necessários:
O problema nos pede para construir uma torre de números seguindo regras estritas de ordenação de dígitos (maior menos o menor) até que um número calculado se repita, finalizando a torre.
Ideia Central
Para resolver este problema, precisamos apenas simular exatamente o que o enunciado descreve. A cada andar da torre:
- Usando divisões inteiras sucessivas por 10, 100, 1000 e a operação de resto da divisão (
%), extraímos os 4 algarismos do número corrente e os guardamos em um vetor. - Ordenamos esses 4 dígitos de forma crescente para gerar (
0177). - Ordenamos esses mesmos 4 dígitos de forma decrescente para gerar (
7710). - Calculamos a diferença: (
7710-0177=7533).
Repetimos esse processo guardando cada resultado em uma lista. Antes de colocar o novo número na torre, verificamos se ele já foi gerado antes. Se sim, a construção acaba.
Se você fez a questão e tentou simular alguns exemplos à mão, deve ter notado um padrão muito estranho: quase todas as torres terminam exatamente no número 6174.
Isso não foi coincidência dos exemplos! Esse processo é uma propriedade matemática real chamada Rotina de Kaprekar, e o número 6174 é conhecido como a Constante de Kaprekar. Para qualquer número de 4 dígitos (desde que eles não sejam todos iguais, como 1111, 2222), essa subtração sempre vai convergir para o 6174 em, no máximo, 7 passos. Sabendo disso, temos a certeza absoluta de que o nosso laço de repetição (while) vai rodar pouquíssimas vezes e nunca vai ficar preso em um loop infinito longo.
Subtarefa 2 –
Esta subtarefa é um presente clássico da OBI para quem está atento. Como o valor de é fixo em 2026, a saída será sempre a mesma. Você poderia inclusive resolver essa subtarefa fazendo as contas no papel (ou testando no seu computador) e criando um código que apenas imprime o resultado estático se N==2026:
Se calcularmos para 2026:
2026->6220 - 0226 = 59945994->9954 - 4599 =53555355->5553 - 3555 =19981998->9981 - 1899 =8082(a partir daqui vira o Exemplo 1)8082->85328532->6174
Um código que simplesmente desse if(n==2026) e printasse essa sequência garantiria 30 pontos sem nem implementar a lógica de ordenação.
Subtarefa 4 –
Para obter os 100 pontos da questão, precisamos criar a simulação geral que funcione para qualquer número inicial no intervalo . Para que a solução fique perfeita nesta subtarefa, precisamos dominar três pontos cruciais:
- Graças à propriedade matemática da Constante de Kaprekar que vimos na curiosidade, o nosso laço
whilevai rodar, no máximo, 8 vezes para qualquer número do planeta. Uma vez que o programa atinge o número 6174, o próximo cálculo será , disparando a repetição e encerrando o código. Portanto, a complexidade de tempo da nossa solução é (tempo constante), executando de forma instantânea e sem qualquer risco de dar Time Limit Exceeded (TLE). - Em soluções com strings, números menores que 4 dígitos (como o 71) exigem o preenchimento manual de zeros. Na lógica matemática de divisão, isso acontece de graça. Ao calcularmos os dígitos de 71, o dígito do milhar é obtido por , o da centena por , o da dezena por e o da unidade por . Com isso, os dígitos isolados tornam-se naturalmente [0, 0, 7, 1], ficando prontos para serem ordenados corretamente.
- Para saber exatamente o momento de parar, precisamos “lembrar” de todos os andares que já construímos. A melhor ferramenta para isso é utilizar as estruturas de busca da STL, como o
std::set(em C++) ou oset(em Python). Sempre que calcularmos o próximo número , jogamos ele nessa estrutura. Se o método de busca indicar que já existia ali dentro, quebramos o loop imediatamente.
