CF-OBI 2023 P1

CF OBI 2023 - Programação Nível 1

Estante

Comentário por Henrique Vianna

Conhecimentos Prévios Necessários:

Nesse problema, queremos distribuir X + Y + Z livros em N prateleiras de tal forma que todas elas tenham a mesma quantidade de livros, sendo que essa quantidade, que chamaremos de Q, deve ser maximizada. Intuitivamente, cada uma das prateleiras receberá Q = \lfloor \frac{X+Y + Z}{N} \rfloor livros, sobrando então X + Y + Z - Q * N livros, que é exatamente igual a (X + Y + Z) \% N. Note que comos os valores fornecidos podem ser grandes (até 10^{18}), 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 con, e então, a quantidade de suco que Letícia vai poder tomar é N - con (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 A, B da entrada, e caso A = 0 (Que significa que o suco não é de abacaxi com hortelã) e B = 1 (Que significa que o suco contém pedaços), então adicionamos +1 em con.

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 G 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 G = 10, 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 O(G*100), ou seja, O(10^7).

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: O(G*100).

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.

(Subtask 2) X \le 10^3

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 N tópicos, cada tópico tem K_i strings e cada string tem tamanho s_i, então procurar o tópico de uma palavra é O(NK_i s_i). Como repetimos o processo X vezes, temos a complexidade final O(XNK_i s_i)

(Subtask 3) X \le 10^5

É 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(s_i*log) (o que fazemos X vezes) e construir todo o map é O(NK_i s_i log), então a complexidade final é O(X s_i log + NK_i s_i log).

Confira o código