Comentário NOIC OBI 2017 - Fase 3 - Programação Nível 2

OBI 2017 - Fase 3 - Programação Nível 2

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.

Taxa

Comentário escrito por Caique Paiva

Conhecimento prévio necessário:

Seja v o vetor em que guardamos como vamos dividir o terreno. Vamos fazer uma dp em intervalo para esse problema! Seja dp[l][r] para ser o menor valor para dividir o terreno em r-l+1 intervalos de tamanho v[l], v[l+1], \cdots, v[r]. Então, primeiro veja que dp[i][i] = 0 para todo i, e então, a transição vai ser

dp[i][j] = max(dp[i][k] + dp[k+1][j] + max(sum(i, k), sum(k+1, j))

Onde k = i e vai até j-1 e sum(i, j) é a soma dos vetores de i até j. Veja que todos essas funções (dp e sum) são cíclicas, então por exemplo, se n = 3, então sum(1, 2) = v[1] + v[2] e sum(2, 1) = v[2] + v[3] + v[1]. No final, basta retornar min(dp[i+1][i]) para todo i.

Para fazer um vetor circular (como é mostrado no código), a ideia é fazer todas as operações módulo n, ou seja, quando fazemos i-1, se i for ficar negativo, fazemos (n+i-1) % n.

Clique aqui para conferir o código

Postes

Comentário escrito por Enzo Dantas

Conhecimento prévio necessário:

Devemos contar quantos postes devem ser substituídos e quantos devem ser consertados. Para fazer isso, devemos contar quantos postes tem uma altura menor que 50 e quantos tem uma altura entre 50 e 84 (a partir de 85 ele pode ser usado normalmente). Assim, vamos manter dois contadores: substitui e conserta. Ao lermos o input, aumentaremos substitui em 1 toda vez que encontrarmos um número menor que 50 e aumentaremos conserta em 1 toda vez que encontrarmos um número maior ou igual a 50 e menor que 85.

No fim, printaremos substitui e conserta.

Clique aqui para conferir o código

Dividindo o Império

Comentário escrito por Arthur Lobo

Conhecimento prévio necessário:

O problema fala que "Alguns pares de cidades estão ligados diretamente por estradas bidirecionais e, por uma antiga tradição, esses pares são escolhidos de maneira que sempre é possível ir de qualquer cidade para qualquer outra cidade por exatamente um caminho (um caminho é uma sequência de estradas).". Isso quer dizer que o grado do problema é uma árvore.

Então, dado uma árvore, o problema pergunta qual a aresta a ser removida tal que o tamanho das 2 árvores geradas após a remoção seja o mais próximo possível.

A ideia aqui vai ser calcular qual é esse valor para cada aresta e pegarmos o mínimo. Para isso, vamos enraizar a árvore em algum vértice, digamos que seja o vértice 1, e definimos S_u = tamanho da subárvore que tem u como raiz. Exemplo:

Para calcular o valor de S_u, basta perceber que o tamanho da subárvore de u é o somatório do tamanho da subárvore dos filhos +1, então podemos fazer uma dfs em que calculamos primeiro os S dos filhos de u e depois S_u.

Perceba que ao deletarmos a aresta entre qualquer vértice u \ne 1 e seu pai, o tamanho das duas árvores resultantes serão S_u e N-S_u, então basta fazermos um for e pegarmos o menor valor de |S_u-(N-S_u)|.

Clique aqui para conferir o código

Arranha-céu

Comentário escrito por Caique Paiva

Conhecimento prévio necessário:

Esse problema é uma aplicação simples de BIT. Vamos codar uma BIT de soma, igual a feita na aula colocada no link acima, e nós sabemos que ela responde a query e faz o update em O(log n). Além disso, vamos guardar o vetor atual, que guarda a quantidade de pessoas em cada apartamento. Na query, retornamos o valor de query(pos) que ele nos dá, e no update, fazemos update(pos, val - v[pos]) com o valor e posição que eles no dá na query, e fazemos v[pos] = val.

Clique aqui para conferir o código

Código

Comentário escrito por Arthur Lobo

Conhecimento prévio necessário:

O problema nos dá uma lista S_1,S_2,...,S_N strings com 10 caracteres cada e nos pergunta se existe qual é a primeira string S_i que é uma substring da contatenação de duas strings S_a,S_b, com 1 \le a,b < i, ou dizer que não existe nenhum.

*Para uma string T, vamos definir T[a:b] como sendo a substring T_{a},T_{a+1},...,T_{b}, ou seja, a substring de a até b de T. Além disso, vamos usar 0-indexado, ou seja, a string T inteira é T[0:T.size()-1].

Parcial 1 ( N \le 100)

Nossa primeira ideia pode ser, para cada i, testar todo par a,b < i e ver se existe alguma substring de S_aS_b igual à S_i. Para cada par, vamos criar uma nova string T = S_aS_b e ver se T[j:j+9] = S_i, para 0 \le j \le 10, se algum for, então encontramos o i.

A para cada par a,b, nós checamos em 10 operações (apesar de ser O(1), 10 é uma constante relativamente alta). Já que existem O(N^2) pares para cada i, e temos N is, a complexidade final fica O(N^3), fazendo na verdade ~10*N^3 operações, que é o suficiente para essa subtask.

Parcial 2 (Sem restrições adicionais)

Vamos dar uma olhada em uma representação visual de quando S_i é uma substring de S_aS_b, com as posições correspondentes em S_i e na contatenação sendo iguais.

Basicamente vai existir um x tal que S_i é a contatenação das últimas x posições em S_a e as primeiras 10-x posições em S_b.

Para ser mais específico, para que i seja uma substring, deve existir algum 0 \le x \le 10 tal que

  • Para algum a < i, S_i[0:x-1] = S_a[10-x:9] (primeiras x posições de i e últimas x de a são iguais).
  • Para algum b < i, S_i[x:9] = S_b[0:9-x] (últimas x posições de i e primeiras x de b são iguais).

Agora basta guardarmos num set pre todos os prefixos das strings que já passamos, e em suf todos os sufixos das strings que já passamos.

Agora quando estamos em i, basta checarmos se existe algum x tal que S_i[0:x-1] está em suf e S_i[x:9] está em pre. Se existir, então i é a resposta. Por fim, colocamos todos os prefixos de S_i em pre e o mesmo com os sufixos em suf.

A complexidade fica O(N*10*log(N).

Clique aqui para conferir o código