OBOI 2023 - Fase 2 - Nível Pleno
Se você quiser se preparar para a OBI, não deixe de conferir o Roteiro de estudos de informática, e também a página de informática do NOIC, com todos nossos materiais.
Para conferir a prova na íntegra, clique aqui.
Par de Palitos
Comentário escrito por Estela Baron
Conhecimento prévio necessário:
Conjunto de testes N <= 500:
Para resolver essa parcial, podemos calcular toda diferença possível entre dois números (lembrando que é necessário ver o módulo). A complexidade fica , a qual não é boa para N = .
Conjunto de testes N <=
Observe que, para um determinado palito, calcular a menor diferença é ver a distância das alturas entre o maior palito menor ou igual ao atual; ou entre o menor palito maior ou igual ao atual. Para fazer isso, podemos ordenar os valores dos palitos em ordem crescente e verificar a diferença entre cada dois valores adjacentes. Para obtermos a nossa resposta, basta armazenar o menor valor encontrado e imprimir. A complexidade da solução fica .
Para conferir o código, clique aqui.
Permutação Máxima
Comentário escrito por Caique Paiva
Conhecimentos Prévios Necessários:
- Algoritmos Gulosos
A ideia do problema é bem simples. Depois de fazer alguns casos na mão (), você vê que a resposta nesses casos vai ser a permutação (para é a resposta, para é a resposta, e assim vai). Durante a prova, a ideia não é provar isso, mas você codar e torcer para isso ser a resposta, já que não tem penalidade para WA. Dito isso, é possível provar, embora ela seja meio complicada, então só recomendo pensar na prova caso você também se interesse por matemática olímpica.
Para implementar, basta criar uma variável , e fazer um for de até fazendo . Veja que pode ficar bem grande, então é importante criar ele como uma variável long long.
Entrega de Mantimentos
Comentário escrito por Enzo Dantas
Conhecimento prévio necessário:
Subtask 1
Para os limites pequenos, podemos calcular em O(N) a resposta para cada coordenada entre (0,0) e (100,100).
Solução completa
Intuitivamente, imaginamos um ponto no plano e qual seria a resposta para ele. Deslizando esse ponto livremente, chegamos a primeira observação: se movermos um ponto para a esquerda/direita, as distâncias verticais não mudam, apenas as horizontais (a situação análoga acontece ao deslizar o ponto para cima/baixo). Logo, é possível calcular as coordenadas X e Y independentemente.
Assim, o problema foi reduzido para o seguinte: dados vários pontos numa linha, retorne um ponto qualquer que minimiza o somatório das distâncias aos outros pontos. Seguindo a idea de imaginar um ponto e deslizá-lo pelo plano, percebemos o seguinte: quando o deslizamos 1 unidade para a direita, por exemplo, o somatório aumenta em 1 para cada ponto a sua esquerda e diminui em 1 para cada ponto a sua direita. Assim, se há mais pontos a direita, vale a pena deslizar para a direita e vice-versa. Logo, o ponto ótimo fica em uma posição tal que há metade dos pontos a sua esquerda e metade a sua direita (ou seja, a mediana), pois qualquer movimentação dele diminuiria ou não mudaria o somatório. Para o caso em que N é par, os dois pontos centrais são ótimos. Como o enunciado pede para maximizar o X em caso de empate, retornamos o mais a direita.
Logo, a solução final consiste em separar as coordenadas X e Y em dois arrays diferentes, ordená-los, e retornar as duas medianas.
Clique aqui para conferir o código
Heróis
Comentário escrito por Enzo Dantas
Conhecimento prévio necessário:
Subtask 1
Para os limites pequenos, podemos fazer um Dijkstra para cada um dos vértices especiais e percorrer todos os pares para ver a menor distância. Complexidade: .
Subtask 2
O grafo dado é uma árvore. Podemos testar, para cada vértice , qual seria o menor caminho caso fosse o lca entre os dois mais pertos. Para isso, usamos uma DP tal que = vértice especial mais perto de na subárvore de .
Casos base: se é um vértice especial, então . Caso contrário, .
Transição: tentamos combinar os dois melhores filhos, ou seja, achamos os dois filhos e que possuem o menor valor de dp+aresta e salvamos que uma possível resposta é . Caso seja um vértice especial, combinamos com o melhor filho, ou seja, .
Clique aqui para conferir o código
Solução completa
A solução completa usa uma ideia conhecida como Dijkstra Multisource. Faremos um único Dijkstra, mas a priority_queue
(ou set
) usada no Dijkstra já começa com vários vértices inicializados com distância zero (ou seja, há vários pontos iniciais, por isso o nome "multisource"). Assim, cada vértice terá salvo a menor distância para o vértice especial mais próximo.
Imagine que cada vértice especial agora possui uma "região" próxima de si tal que todos os vértices nessa região são mais próximos dele do que de qualquer outro vértice especial. Testaremos cada aresta que conecta duas regiões diferentes, ou seja, salvamos que é uma possível resposta e pegamos a menor entre todas elas. Note que, para saber se uma aresta conecta duas regiões diferentes, precisamos salvar para todo vértice o índice do vértice especial mais próximo, o que pode ser feito facilmente no Dijkstra.
Clique aqui para conferir o código
Bonsai
Comentário por Henrique Vianna
Conhecimento prévio necessário:
Perceba que o enunciado se resume ao seguinte: Dada uma árvore em que os vértices possuem valores (que podem inclusive ser negativos), maximize após a remoção de até vértices, juntos às suas respectivas subárvores. Na resolução desse exercício, analisaremos cada uma das parciais, antes de chegar à solução final.
Parcial 1: A árvore é uma linha, ou seja, .
Nessa parcial, podemos imaginar a a árvore como um vetor, em que as operações que podemos fazer é remover um sufixo seu. Perceba entretanto, que o valor de é irrelevante: sempre existe uma solução ótima em que exatamente um sufixo é removido, podendo esse ser nulo. Por consequência, sempre manteremos um prefixo desse vetor, ou seja, a resposta é simplesmente a maior soma de prefixo de .
Parcial 2: e
Para resolver essa parcial, faremos uso de uma dp, sendo que:
é o minimo que consigo remover com exatamente operações entre os vértices da subárvore de .
A recorrência dessa dp é relativamente simples. Faremos uso de uma segunda dp, , para nos auxiliar nessa recorrência:
é o minimo que consigo remover em operações considerando os primeiros filhos de .
A recorrência de é bastante similar à DP clássica da Knapsack: deve-se brutar, para o filho atual, quantas operações serão feitas dentro de sua subárvore. Chamaremos esse numero de . Sendo assim:
, tal que
Ao final, para termos os valores de de fato, basta fazermos:
, sendo o numero de filhos de .
A resposta é simplesmente , com .
Parcial 2: Sem restrições adicionais.
A acima, apesar de ser suficiente para a parcial 2, não é rápida o suficiente para obter-se pontos, haja vista sua complexidade de . Precisamos, portanto, otimizá-la. Uma maneira inteligente de fazer isso é "linearizar" a árvore, fazendo uma similar a essa em seu Euler Tour. Para tanto, basta calcularmos o e de cada um dos vértices numa inicial. Calcularemos a nos vértices ordenados por . Define-se:
é o minimo que consigo remover com exatamente operações entre os últimos vértices do Euler Tour.
Vale notar que estamos calculando a nossa no sufixo, ou seja, passando do ultimo vértice do Euler Tour ao primeiro. A recorrência, portanto, é dada por:
, sendo que guarda a soma dos na subárvore de .
A resposta é calculada da mesma forma que na parcial . Sendo assim, conseguimos resolver o problema em .
Para melhor compreensão, confira o código aqui.