Problema D - Jantar para dois mil

Este é um problema de interação.
Ao contrário dos outros problemas em que deves fazer leitura de dados e escrita do output, neste problema deves interagir com o avaliador através da implementação de uma função e da interação com as funções fornecidas.

Agora que as ONI estão quase a terminar, está na hora do grande jantar de despedida. Toda a gente vai estar presente, o Gabriel, a Joana, o João, o Duarte, o Marco, ... no total vão estar N pessoas presentes, entre concorrentes, ex-concorrentes e público interessado.

O jantar será servido numa grande mesa de N lugares, com os lugares distribuidos sequencialmente, como mostra a imagem seguinte:

Antes de começar o jantar, cada pessoa irá sentar-se no seu lugar e esperar que o seu prato chegue. Visto que há N pessoas, os pratos vão saindo um a um, a cada minuto que passa. Como é sabido, é boa educação esperar que toda a gente na mesa tenha o seu prato antes de se começar a comer. Visto que a mesa é comprida e há tanta gente, nem toda a gente consegue ver toda a gente e por isso a pessoa i só espera pelas pessoas num raio de Ri lugares (ou seja, as pessoas à sua direita e esquerda a menos de Ri lugares de distância). A imagem seguinte representa os raios de espera de cada pessoa:

No exemplo anterior, temos:

Visto que a ordem de chegada dos pratos pode ser qualquer uma, cada pessoa pode demorar um tempo diferente até começar a comer. Por exemplo, considera a ordem de chegada dos pratos seguinte: 1, 3, 2, 5, 4, 6, ou seja, no minuto 1 chega o prato para o lugar 2, no minuto 2 chega o prato para o lugar 3 e por ai fora. Neste caso, temos:

A equipa de catering precisa de saber o tempo de espera em diferentes momentos (exatamente Q momentos), para perceber se a ordem que escolheram para servir os pratos foi boa ou não. Como algumas pessoas ainda podem estar à espera para comer, a equipa a qualquer momento apenas quer saber a soma dos tempos de espera das pessoas que já estão a comer. Consegues ajudá-los?

O Problema

Dado o número de pessoas a participar no jantar N, a ordem de chegada dos pratos, responder a um conjunto de Q perguntas sobre a soma dos tempos de espera em diferentes momentos.

Ficheiros para Download

Podes começar por descarregar os ficheiros correspondentes à tua linguagem (ou um arquivo zip contendo tudo):

Linguagem Ficheiro a implementar Ficheiro com avaliador exemplo Ficheiros auxiliares Input para avaliador exemplo
C resolver.c avaliador.c avaliador.h input.txt
C++ resolver.cpp avaliador.cpp
Java resolver.java avaliador.java ------

Nota que a implementação do avaliador a usar nos testes oficiais será diferente, mas podes esperar o mesmo comportamento.

Implementação

Deves submeter um único ficheiro que implementa três funções:

O avaliador começará por chamar a função iniciar(N, R) e depois chamará as funções chegada(i) e pergunta() alternadamente.

Para isso deves usar o ficheiro resolver.{c,cpp,java,pas} que descarregaste, colocando no interior das funções o teu código. Podes acrescentar outras funções, mas devem ficar todas neste ficheiro que é o único que deves submeter.

Funções a implementar:
C/C++:void iniciar(int N, int Q, int R[MAXN]);
Java:void iniciar(int N, int Q, int[] R);
C/C++/Java:void chegada(int i);
C/C++:long long int pergunta();
Java:long pergunta();

Notem ainda que o tipo de inteiro para a função pergunta() é long long int no caso de C/C++ e long no caso de Java.

A vossa função não deve ler nem escrever para os canais de entrada/saída padrão.

Exemplo

Imagina que N = 6 pessoas com raios de espera 2, 1, 2, 4, 1, 1, respetivamente (como no exemplo a cima), serão feitas Q = 3 perguntas. A função iniciar que deves implementar será chamada como resolver(6, 3, {2, 1, 2, 4, 1, 1}).

Uma possível execução seria a seguinte (com a ordem das chamadas a ser de cima para baixo):

InvocaçãoResultadoDescrição
chegada(1)--
chegada(3)--
chegada(2)--
pergunta()2As pessoas 1 (espera 2 minutos) e 2 (espera 0 minutos) já começaram a comer.
chegada(5)--
chegada(4)--
pergunta()5As pessoas 1 (espera 2 minutos), 2 (espera 0 minutos) e 3 (espera 3 minutos) já começaram a comer.
chegada(6)--
pergunta()8Todos já estão a comer, para um tempo de espera total de 8.

Reparem que a ordem de chegada dos pratos é igual à do exemplo a cima.

Restrições

São garantidos os seguintes limites em todos os casos de teste:
1 ≤ N ≤ 100 000Número de pessoas.
1 ≤ Q ≤ 100 000Número de perguntas.
0 ≤ Ri ≤ NRaios de espera.

Avaliação e Casos de Teste

Cada grupo tem um número de pontos associado e um conjunto de restrições adicionais. Os grupos são os seguintes:

Grupo Número de Pontos Restrições adicionais
1 25 N ≤ 1 000, Q ≤ 1 000
2 20 Q = 1
3 10 Q ≤ 10
4 20 Todos os Ri são iguais
5 25 -

Testes no vosso computador

É disponibilizado um avaliador exemplo em cada linguagem (avaliador.{c,cpp,java,pas}) que pode ser utilizado para testar a vossa submissão. Para C/C++ está ainda disponível um ficheiro auxiliar (para C/C++ o avaliador.h). Este avaliador não corresponde ao utilizado pelo sistema de avaliação.

Este avaliador começa por receber como input um inteiro N e um inteiro Q correspondendo, respetivamente, ao número de pessoas e perguntas. Segue-se uma linha com N inteiros entre 1 e N, separados por espaços, que representam os raios de espera de cada pessoas (por ordem de lugar).

Seguem-se N + Q linhas, cada uma contendo ou: C i, indicando que chegou o prato para o lugar i; P, indicando que foi feita uma pergunta. Devem garantir que o número de chegadas é exatamente N e de perguntas Q.

O avaliador irá automaticamente invocar a função iniciar(N,Q,R) por vocês implementada e chamará de seguida as funções chegada(i) e pergunta() alternadamente, de acordo com o dado no input. O avaliador irá imprimir o resultado de cada pergunta para uma linha diferente, pela ordem do input (devem comparar com o resultado esperado para o input dado).

Disponibilizamos um ficheiro input.txt que contém o caso de exemplo referido a cima, cujo output correto deve ser:

2
5
8

Um exemplo de teste na tua máquina (supondo que tens os compiladores oficiais instalados) seria o seguinte:

LinguagemCompilarExecutar com o exemplo
Cgcc -Wall avaliador.c resolver.c./a.out < input.txt
C++g++ -Wall avaliador.cpp resolver.cpp./a.out < input.txt
Javajavac avaliador.java resolver.javajava avaliador < input.txt

Prova de Seleção para as IOI'2018
Departamento de Ciência de Computadores
Faculdade de Ciências da Universidade do Porto
(10 de Junho de 2018)