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á:
,