TFC 2021
Para conferir a prova na íntegra, clique aqui.
Amizade
Comentário escrito por Estela Baron
Conhecimento prévio necessário:
Para este problema, precisamos ler a entrada e, para cada , verificamos se a diferença entre e é menor ou igual a . Observe que é necessário comparar o valor absoluto da diferença, então podemos usar a função , que retorna o valor absoluto de um número.
Clique aqui para conferir o código
Livros
Comentário escrito por Estela Baron
Conhecimento prévio necessário:
Nesse problema, é fundamental analisar os limites e as subtasks, porque, caso a ideia para a questão inteira não esteja clara, ainda é possível conseguir pontos das parciais.
A princípio, uma das primeiras ideias que podemos ter para resolver o problema é, para cada e , adicionar em um vetor, em que cada posição representa um dia e guarda a quantidade de livros lidos naquele dia, +1 em todos os dias de até , por meio de um .
No entanto, apesar dessa solução atender a subtask 2, há diversos problemas com a complexidade e a memória. Para cada livro, no pior caso, teríamos que percorrer posições, resultando em uma complexidade de , a qual estouraria o limite de tempo - e também não tem como criar um vetor com posições, por causa da memória.
Primeiro, vamos ignorar o problema de acessar as posições e concentrar em como não ter que percorrer todas as posições quando estivermos analisando um livro. Para isso, vamos utilizar um truque muito comum para soma em intervalos contínuos, que é adicionar +1 na posição de início (no caso ) e somar -1 na posição imediatamente após a última do intervalo (no caso ). No final, quando fazemos a soma acumulada, todas as posições de até o final ganham + 1 e todas as posições de perdem -1, totalizando um acréscimo de 1 no intervalo desejado e 0 no restante. Com isso, conseguimos adicionar um livro em todos os dias do intervalo em e, no final, obtemos a quantidade exata de livros lidos em cada dia - obtendo, assim, a resposta.
Agora, vamos resolver o problema do acesso às posições. Observe que só precisamos de duas posições para somar em um intervalo - o início e o fim + 1. Isso nos possibilita comprimir as coordenadas, ou seja, transformamos todos os dias que precisamos ( e ) em novos índices, de forma que tenha no máximo posições no vetor que usamos para calcular a soma acumulada. Podemos fazer isso colocando cada e cada em um e ordenar. Após isso, com um map, atribuímos um novo índice para esse dia e adicionamos +1 ou -1 a essa posição.
Por último, fazemos uma soma de prefixos e salvamos o maior resultado que aparece.
Clique aqui para conferir o código
Figurinhas
Comentário escrito por Estela Baron
Conhecimento prévio necessário:
Observe que existem exatamente arestas ligando bancas diferentes, isso é uma das propriedades de uma árvore, portanto, o problema envolve árvores! Outra observação legal de se fazer ao observar as restrições é que há no máximo 20 tipos de figurinhas. Tal informação nos permite representar um conjunto de figurinhas em um inteiro ao invés de usar um - aula de bitmask. Outra constatação importante é que a banca de origem é fixa para todas as consultas, isso nos permite pré-calcular o resultado a quantidade de figurinhas diferentes para cada banca e depois só responder as consultas. Ao fazer esse passo, evitamos ter que calcular cada consulta individual - o que tornaria a nossa complexidade quadrática, ou seja, incorreta.
Portanto, só precisamos fazer uma a partir do nosso ponto de origem. Para fazer isso, notamos que, como só há um caminho de para , se é possível chegar em a partir de , então recebe todas as figurinhas que consegue adquirir partindo de . Para fazer essa junção das figurinhas de com as de , podemos utilizar o operação binária OU (|) - assim, se tivermos ou bit aceso na posição , que representa a figurinha do tipo , a representação binária resultante da operação também terá. Exemplo: suponha que = e = , temos que tem as figurinhas dos tipos 2 e 4 (indexa do 0 da direita para a esquerda) e tem as figurinhas dos tipos 1, 3 e 4. Quando fazemos a junção desses dois conjuntos - que representa quais figurinhas conseguimos de até - obtemos , ou seja, é possível coletar as figurinhas dos tipos 1, 2, 3 e 4. Assim, atualizamos a para e continuamos para as outras bancas.
Ao final, para cada consulta, basta acessarmos o número em e descobrir quantos bits estão acesos - a nossa resposta. Para fazer esse último passo, como podemos ter no máximo 20 bits acesos, é possível realizar um e checar por meio da operação binária AND (&) se & é diferente de zero. Se for, significa que o bit está aceso, ou seja, temos uma figurinha do tipo e que podemos adicionar uma figurinha a nossa resposta. No fim, teremos a quantidade exata de figurinhas diferentes que podemos obter do caminho de até .
Clique aqui para conferir o código
Anagrama
Comentário escrito por Enzo Dantas
Conhecimento prévio necessário:
Enunciado
Primeiramente, é necessário entender bem o enunciado e entender o que ele pede, pois ele é, de fato, confuso. O enunciado diz "o número máximo de possíveis pares de anagramas que poderiam ser formados considerando todas as possibilidades de correspondência". Utilizando o exemplo fornecido, entre todos os pares das palavras "dados", "caixa" e "testa", é possível formar um par de anagramas com 3 deles. Note que é possível formar exatamente 3_escolhe_2 = = 3 pares com 3 palavras, o que significa que qualquer par pode formar um par de anagramas nesse caso. Isso indica que "dados" pode formar um anagrama com "caixa" ao mesmo tempo que pode formar um anagrama com "testa", apesar de não usar o mesmo embaralhamento, e as duas possibilidades são contadas na resposta. Ou seja, cada par é analisado individualmente. A pergunta então é "quantos pares de palavras, analisados individualmente, poderiam formar um par de anagramas?"
Checagem
A etapa mais importante da solução é saber checar se é possível que um par de palavras forme um par de anagramas. Analisando os casos teste e tendo em mente a condição para que duas palavras sejam um par de anagramas, observamos o seguinte padrão: as palavras "caixa" e "testa" possuem um letra que se repete uma vez ('a' e 't') e todas as outras não se repetem, além de possuírem o mesmo tamanho.
A mesma situação acontece na palavra "dados". Observe que não importa como as letras estão organizadas, tudo que importa para que duas palavras sejam um par de anagramas é a frequência das letras. Como é possível transformar uma letra em qualquer outra letra usando o embaralhamento, a condição final ignorará as letras em si e focará na frequência delas.
A condição final é a seguinte: para que duas palavras possam formar um par de anagramas, a quantidade de letras cuja frequência é igual a deve ser igual em ambas . Ambas as palavras "acbcb" e "ddefe", por exemplo, possuem duas letras com frequência igual a 2 e uma letra com frequência igual a 1 e, portanto, podem formar um par de anagramas.
Em relação à implementação, é possível guardar, para cada frequência, quantas letras a possuem, mas aqui utilizaremos a seguinte ideia (que é mais simples de implementar): para calcular as frequências das letras de uma palavra, percorreremos a palavra e salvaremos em um map a frequência de cada letra. Feito isso, vamos percorrer esse map e adicionar as frequências em um vector que vamos chamar de . Como comparar esse vector com o vector de outra palavra? Vamos ordená-los. Assim, caso os 's sejam exatamente iguais, então esse é um par válido.
Exemplo:
string = abbfe
map = , , ,
aux = e, após o sort,
Solução final
Para resolver a subtask 1 () , basta rodar o algoritmo acima entre as duas strings. Já para a subtask 2 (), é possível percorrer cada par e rodar o algoritmo de checagem neles, o que tem uma complexidade de aproximadamente . Para a solução final, perceba que, se palavras possuem o mesmo vector , então escolher qualquer duas dessas palavras formará um par válido. Ou seja, é possível formar pares válidos com essas palavras. Sendo assim, vamos salvar a frequência de cada vector em um map e para cada um adicionaremos na resposta. A complexidade final é tal que é o tamanho da maior string. Como , a complexidade é aproximadamente . É possível ainda reduzir essa complexidade para usando um unordered_map
em vez de um map normal, mas é desnecessário nesse caso.