Seletiva IOI 2020 - 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 2019 foi feita para a IOI 2020
Aptidões
Subtask 1-5 ()
Primeiro vamos ver como resolver o problema tendo apenas uma query. Sendo assim, vamos falar que o valor de cada competidor é ; agora queremos selecionar os competidores de forma a maximizar a soma dos valores.
Podemos ver o problema como um grafo bipartido, em que ligamos o competidor (parte da esquerda do grafo) com todos os baldes (parte direita do grafo). Temos que escolher algumas arestas de como que cada vértice tenha no máximo 1 aresta escolhida conectando a ele e a soma dos valores dos vértices da esquerda seja máxima.
Isso parece com algum outro problema? Sim, queremos encontrar um matching com a soma máxima. Não só um matching, mas um matching máximo com soma máxima, ou seja, o matching que estamos procurando tem o mesmo tamanho do matching máximo (com maior quantidade de vértices).
Isso acontece porque se temos algum caminho aumentante, então podemos aumentar o tamanho do matching (e portanto aumentar a soma dos valores); então o matching de soma máxima também é um matching máximo.
Vamos pensar em como normalmente fazemos o problema geral de bipartite matching máximo: temos os vértices em alguma ordem arbitrária e vamos chamando uma função que tenta adicionar o vértice no matching encontrando um caminho aumentante partindo de , e portanto, colocar ele no matching sem remover nenhum vértice que já está no matching. Perceba que quando eu chamo , eu já tentei colocar no matching todos os vértices , então ao tentar colocar , não pode acontecer se eu remover algum deles do matching.
Primeiro, vamos criar um array para reindexar os competidores ordenando eles em ordem decrescente de : . Perceba que sempre vale a pena colocar o vértice no matching (considerando que ele tem pelo menos uma aresta), porque caso ele não esteja, podemos remover algum outro vértice com um valor menor e adicioná-lo. Considerando que está no matching, sempre vale a pena tentar colocar o no matching de um modo que não removemos o pelo mesmo motivo.
Continuando desse jeito, sempre vale a pena tentar colocar o vértice no matching sem remover os vértices . Ou seja, vamos tentando adicionar os vértices na ordem decrescente de valor chamando , depois ... até e somando quando conseguimos de fato adicionar o vértice.
Seja o conjunto dos vértices no matching usando apenas vértices até o e a soma dos valores desses vértices.
Digamos que temos já sabemos e queremos encontrar .
Já que o matching com soma máxima é um matching máximo, ao adicionar o vértice temos 2 casos: não vale a pena colocar o vértice em , pois caso ele fosse colocado, eu teria que remover um vértice que já está em e tem o valor maior que .
Portanto, .
o tamanho do matching máximo aumentou em 1, então existe um caminho aumentante partindo de .
Sabemos que a diferença é no máximo e podemos chegar nesse valor se simplesmente adicionamos ao matching sem remover nenhum vértice que já está nele usando o caminho aumentante.
Portanto, .
Cada vez que chamamos que chamamos é pois resetamos o vetor de marcados e no pior dos casos passamos uma vez por todos os vértices que já estão no matching até agora, nunca por algum antes de que não está no matching até agora. Então no total chamamos vezes, totalizando para uma única query.
Obs: Isso passa em todas as parciais até a 5.
Subtask 6-8 ( e )
Essas subtasks possuem uma solução muito diferente do problema inteiro e das subtasks anteriores, então não iremos falar dela nesse editorial. A ideia usada nelas é de fazer convex hull para encontrar os melhores competidores em cada query.
Para é um convex hull mais direto, para precisamos fazer camadas do convex hull. Ou seja, faz um convex hull, tira todos os vértices que estão nele, faz outro convex hull com os que sobraram, tira eles de novo... Se um competidor não está em nenhuma das 15 camadas, então sempre vai existir pelo menos 15 competidores melhores do que ele.
Subtask 9 (Sem restrições adicionais)
Não temos tempo para fazer um matching bipartido para cada query, então temos que fazer algo mais inteligente.
Primeiro, o valor em si de e não importa, o que importa para saber qual o matching máximo é a razão . Além disso, o valor de cada também não importa, e sim a ordem deles. Cada valor de vai equivaler a um vetor , mas perceba que muitos vão ter o mesmo . Quantas ordens diferentes podem existir?
Teremos no máximo ordens diferentes porque cada par vai trocar no máximo uma vez enquanto aumenta. Considerando que e , então começa ganhando (quando é pequeno) e para encontrar quando eles trocam: . Eles trocam quando , então quando chegarmos nisso, basta remover a aresta de e chamar para tentar adicionar ele no matching (caso ele não já esteja).
No total, fazemos chamadas à função e respondemos cada query em , então no total fica .