Seletiva IOI 2018 - Dia 3
Se você quiser se preparar para a OBI e seletiva, 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.
Clique aqui para conferir a prova na íntegra *A seletiva da OBI 2017 foi feita para a IOI 2018
Cabo de Guerra
Comentário escrito por Caique Paiva
Conhecimento prévio necessário:
Primeiro, veja que, se , nós poderiamos brutar todas as somas possíveis, e conseguiriamos fazer o problema em
. Então, temos que achar uma maneira mais esperta de brutar as respostas. Com isso, perceba que fazer uma Knapsack dp é uma maneira de brutar todas as somas. Quando fazemos ela para achar uma soma máxima por exemplo, nós sempre salvamos a maior resposta anterior para não temos problema de complexidade, mas no final, nós testamos todos os casos possíveis.
Com essa observação, perceba que também é pequeno, então vamos fazer a seguinte dp:
Onde ela vai guardar se, no intervalo usando
números, a soma dá igual a
(A dp é 1 se é verdade, e é 0 caso contrário). Veja que
e
, ou seja, a quantidade de memória que estamos utilizando é
, que cabe na memória e no tl. Com isso, o caso base da dp vai ser
,
ou
e
com
e
ou
. Então, a transição vai ser
(Os raciocínios são iguais a de uma knapsack padrão).
Com isso, como achar a solução do nosso problema. Bem, tem uma forma mais rápida que essa com matemática, mas uma possibilidade é ver que se , então o valor de um grupo vai ser
, e o de outro vai ser
, onde
, e a diferença entre os dois grupos vai ser abs(SUM-2*i), então, basta criar uma variável auxiliar
, e se
, então fazemos
.
Clique aqui para conferir o código
Equipe
Comentário escrito por Estela Baron
Subtask 20 pontos: 1 <= N <= 20
Conhecimento prévio:
Como é pequeno, podemos simular todas as possibilidades de equipes. Para cada conjunto, vemos se a equipe é válida, ou seja, vemos se cada tema é dominado por pelo menos uma pessoa e se não é por pelo menos uma. Caso a equipe seja válida, atualizamos a resposta caso ela contenha o menor número de pessoas. Para gerar todos os subconjuntos, podemos utilizar uma bitmask, em que cada pessoa é representada por um bit. A complexidade fica
.
Subtask 80 pontos: 1 <= N <= 200
Conhecimento prévio:
Para cada pessoa, vamos representar as suas habilidades por meio de uma bitmask: mask_pessoa: se o for dominado, então o
estará ligado. Além disso, vamos criar também uma bitmask inversa: inv para representar os assuntos não dominados: todo assunto não dominado tem o bit aceso. Com isso, podemos representar um conjunto de assuntos dominados ou não como um inteiro. A partir disso, vamos fazer: dp[mask assuntos dominados][mask assuntos não dominados] = menor quantidade de pessoas para ter as duas masks.
Para calcular os estados, vamos fazer um loop e passar por cada pessoa:
- em cada pessoa, vamos simular todas os estados possíveis, ou seja, desde dp[0][0] até dp[
][
]
- para cada estado, vemos se vale ou não a pena adicionar a pessoa à equipe: fazemos dp[
][
] = min ( dp[
][
], 1 + dp[(
| mask_pessoa) - mask_pessoa][(
| inv) - inv]
- Observe que precisamos realizar a operação OR| para só retirar o que precisamos.
Assim a resposta estará em dp[][
]
A complexidade fica .
Clique aqui para conferir o código
Tribo
Comentário escrito por Henrique Vianna
Conhecimento prévio necessário:
Perceba, primeiramente, que o problema pode ser reduzido ao seguinte: Dada uma árvore com pesos nas arestas, escolha um subconjunto de exatamente vértices de tal forma que a soma dos pesos das arestas necessárias para interligá-los seja mínima.
Intuitivamente, trata-se de um problema de DP em árvore. Define-se então:
é o minimo custo possível para escolher exatamente
vértices na subárvore de
, sendo
um desses escolhidos.
Imagine agora que queremos calcular a para um vértice especifico que chamaremos de
. Para tanto, teremos que "juntar" as respostas de seus filhos. Logo, faremos uso de uma segunda
, de tal forma que:
é o minimo custo possível para escolher exatamente
vértices, considerando os
primeiros filhos de
.
Inicialmente, todos os valores de devem ser iguais a infinito, exceto
, que deve ser igual a
. A recorrência de
é bastante similar à DP clássica da Knapsack: deve-se brutar, para o filho atual, quantos vértices de sua subárvore serão escolhidos. Chamaremos esse numero de
. Sendo assim:
, tal que
Na recorrência acima, assim como no código a seguir, é o filho sendo processado e
é o peso da aresta entre
e
. Ao final, para termos os valores de
de fato, basta fazermos:
, sendo
o numero de filhos de
.
Note, entretanto, que assim como na Knapsack podemos facilmente eliminar a primeira informação da , utilizando a técnica conhecida como Memory Saving Trick. Basta passarmos por
em ordem decrescente, assim como feito no código abaixo.
A resposta final será:
,