CF OBI 2023 - Programação Nível 1
Estante
Comentário por Henrique Vianna
Conhecimentos Prévios Necessários:
Nesse problema, queremos distribuir livros em prateleiras de tal forma que todas elas tenham a mesma quantidade de livros, sendo que essa quantidade, que chamaremos de , deve ser maximizada. Intuitivamente, cada uma das prateleiras receberá livros, sobrando então livros, que é exatamente igual a . Note que comos os valores fornecidos podem ser grandes (até ), temos que ler nossas variáveis como long long.
Clique aqui para conferir o código
Suco
Escrito por Caique Paiva
Conhecimentos Prévios Necessários:
Primeiro, na solução, vamos contar a quantidade de sucos contaminados, chame esse valor de , e então, a quantidade de suco que Letícia vai poder tomar é (Que é a quantidade de suco menos os sucos contaminados). Então, para contar a quantidade de sucos contaminados, basta fazer um for para passar por cada da entrada, e caso (Que significa que o suco não é de abacaxi com hortelã) e (Que significa que o suco contém pedaços), então adicionamos em .
Clique aqui para ver o código.
Garrafões
Comentário escrito por Estela Baron
Conhecimentos prévios necessários:
Subtask M = 1 e 1<= G <= 10:
Note que só pilhas com 1 ou 5 garrafões poderão ser utilizadas, pois temos no máximo 10. Então, veja que até 4 só tem uma maneira: todo mundo igual a 1. A partir de 5, ganhamos mais uma possibilidade: usar a pilha com 2 camadas. De 5 até 9, vamos ganhando toda vez mais uma maneira de arranjar (tudo com 1, e uma com 5 e o resto com 1 - variando as posições). Com 10 garrafões, podemos fazer tudo com pilhas de 1; 1 pilha com 5 e o resto com 1; 2 pilhas de 5.
Subtask M = 2 e 1 <= G <= 10:
Note que, como queremos minimizar, de 1 até 4 garrafões temos só uma possibilidade - todas pilhas com 1 garrafão. A partir de 5 até 9, podemos utilizar uma pilha com 2 camadas, um total de 5 garrafões. Com isso, o restante vira pilhas de 1 garrafa. Logo, basta contar a quantidade de pilhas totais: (1 + G-5), pois seria a mesma coisa de contar todos os arranjos das posições da pilha com 2 camadas. Por fim, com , a única possibilidade para a menor quantidade de pilhas é quando temos duas com 2 camadas (cada pilha com 5).
Subtask M = 1 e 1 <= G <= 100000:
Para essa tarefa, vamos usar uma dp. Vamos começar declarando um vetor dp[quantidade de garrafões] = número de formas de arranjar as pirâmides. Para calcular essa dp, vamos fazer uma abordagem iterativa: vamos calcular o caso base e, para todo outro estado, vamos usar algum estado anterior. O caso base é dp[0] = 1, pois só há uma maneira de ter 0 garrafões: que é não colocando nenhum.
Por exemplo, digamos que já calculamos todos os valores de 0 até 20. Então, se eu quero calcular o estado dp[21], eu vou "testar" todos os tamanhos de pilhas que podem estar no final. Quando a última pilha tiver 1 camada, temos que dp[21] += dp[21 - 1]. Quando a última pilha tiver 2 camadas (5 garrafões) : temos que dp[21] += dp[21 - 5]. Quando tiver 3 camadas: dp[21] += dp[21 - 14]. Quando tiver 4 camadas, não poderemos ter, pois o número de garrafões seria igual a 30, o que é maior que o nosso número no exemplo (21). Então, no fim, temos que dp[21] = dp[20] + dp[16] + dp[7].
Assim, podemos usar a estratégia do exemplo para calcular todos os estados: podemos pré-calcular a quantidade de garrafões para cada tamanho de pilha ou podemos usar a fórmula da soma de quadrados: a soma dos n primeiros quadrados é igual a n*(n+1)*(2*n+1)/6. Depois, para cada estado, adicionamos o valor que obtemos quando tiramos a quantidade de uma pilha. A resposta será dp[G]. Lembre de sempre tirar o módulo. Note que o número de camadas não passa de 100 - no código final, o limite ficou 200, mas é só uma aproximação. A complexidade final fica , ou seja, .
Subtask sem restrições adicionais:
Observe que esta subtask é a junção da anterior com a do M = 2 e 1 <= G <= 100000. Vamos utilizar a mesma abordagem vista anteriormente de dp iterativa, mas com uma pequena mudança: ao invés de cada estado guardar somente um valor, agora o vetor guardará um pair<int,int>: dp[quantidade de garrafões] = {menor quantidade de pilhas, número de formas de arranjar as pirâmides com a menor quantidade de pilhas}.
O caso base é dp[0] = {0,1}, pois não temos nenhuma pilha com 0 garrafão e temos 1 possibilidade: não colocar ninguém. Para cada novo estado (i), vamos utilizar a mesma ideia de retirar a última pilha, ou seja, tirar uma quantidade k de garrafões e ver se dp[i-k].first + 1 é a menor quantidade de pilhas que eu consigo com i garrafões. Se for, eu adiciono o valor de dp[i-k].second - quantidade de maneiras- em dp[i].second. Com isso, a nossa resposta será dp[G].second. Lembre de tirar o módulo e, da mesma forma, o limite de camadas não passa de 100. A complexidade final fica igual à outra subtarefa: .
Para conseguir todos os pontos, só precisa juntar o M = 1 e o M = 2 em um único código: pode fazer duas condições diferentes e tratar cada caso.
Clique aqui para conferir o código.
Machine Learning
Comentário escrito por Enzo Dantas
Conhecimento prévio necessário:
A ideia principal do problema é bem direta: percorremos as palavras do artigo, vemos em qual tópico cada palavra está e contamos qual tópico mais aparece.
Um jeito de descobrir em qual tópico uma certa palavra está é procurar tópico por tópico e palavra por palavra dentro de cada tópico.
Complexidade: existem tópicos, cada tópico tem strings e cada string tem tamanho , então procurar o tópico de uma palavra é . Como repetimos o processo vezes, temos a complexidade final
É fácil ver que é possível saber em qual tópico uma certa palavra está de uma maneira bem mais rápida. Quando estamos lendo os tópicos e suas respectivas palavras, salvamos o tópico de cada palavra em um map. Assim, podemos acessar o tópico de qualquer palavra fazendo map[palavra].
Complexidade: acessar cada palavra no map é (o que fazemos vezes) e construir todo o map é , então a complexidade final é .