Soluções para o Concurso AGC011

A - Ônibus Aeroportuário

Algoritmo guloso processa passageiros ordenados. Cada ônibus parte no tempo de chegada de um passageiro. Ao processar cada passageiro, libera-se o mínimo de ônibus necessário para acomodá-lo, respeitando o intervalo máximo de espera.

#include <algorithm>
#include <cctype>
#include <cstdio>
using namespace std;
typedef long long ll;

ll leitura() {
    int sinal = 1; ll num = 0; char c = getchar();
    while(!isdigit(c)) { if(c == '-') sinal = -1; c = getchar(); }
    while(isdigit(c)) num = num * 10 + (c - '0'), c = getchar();
    return sinal * num;
}

const int MAX = 100005;
int passageiros, capacidade, intervalo, tempos[MAX], inicio;

int main() {
    passageiros = leitura(), capacidade = leitura(), intervalo = leitura();
    for(int idx = 0; idx < passageiros; idx++) tempos[idx] = leitura();
    
    sort(tempos, tempos + passageiros);
    int onibus = 0;
    inicio = 0;

    for(int idx = 0; idx < passageiros; idx++) {
        while(inicio <= idx && tempos[idx] > tempos[inicio] + intervalo) {
            int vagas = capacidade;
            int limite = tempos[inicio] + intervalo;
            onibus++;
            while(vagas-- && inicio <= idx && tempos[inicio] <= limite) inicio++;
        }
    }
    printf("%d\n", onibus + (passageiros - inicio + capacidade - 1) / capacidade);
    return 0;
}

B - Criaturas Coloridas

Ordena-se as criaturas por tamanho. Uma criatura sobrevive se conseguir consumir todas menores e a próxima maior. Verifica-se sufixos: se a soma acumulada até uma posição é suficiente para consumir a criatura seguinte.

#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;

ll ler() {
    ll num = 0; char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') num = num * 10 + (c - '0'), c = getchar();
    return num;
}

const int MAXN = 100005;
ll tamanhos[MAXN], prefixo[MAXN];
int total;

int main() {
    total = ler();
    for(int i = 0; i < total; i++) tamanhos[i] = ler();
    sort(tamanhos, tamanhos + total);
    
    for(int i = 0; i < total; i++) 
        prefixo[i] = (i > 0 ? prefixo[i-1] : 0) + tamanhos[i];
    
    int sobreviventes = 1;
    for(int i = total - 2; i >= 0; i--) {
        if(prefixo[i] * 2 < tamanhos[i+1]) break;
        sobreviventes++;
    }
    printf("%d\n", sobreviventes);
    return 0;
}

C - Grafo Quadrático

Modela pares de vértices (a,b) como nós. Componentes conexas originais influenciam conectividade: componentes bipartidas contribuem diferentemente. Isolados geram pares específicos. Contabiliza-se componentes bipartidas e não-bipartidas.

#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;

ll ler() {
    ll num = 0; char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') num = num * 10 + (c - '0'), c = getchar();
    return num;
}

const int MAX = 100005;
vector<int> adj[MAX];
int vertices, arestas;
bool visitado[MAX], cor[MAX];

bool dfs(int u, int c, int &cont) {
    visitado[u] = true;
    cor[u] = c;
    cont++;
    bool bipartido = true;
    for(int v : adj[u]) {
        if(!visitado[v]) bipartido &= dfs(v, c^1, cont);
        else if(cor[u] == cor[v]) bipartido = false;
    }
    return bipartido;
}

int main() {
    vertices = ler(), arestas = ler();
    for(int i = 0; i < arestas; i++) {
        int u = ler(), v = ler();
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    
    int isolados = 0, bipartidas = 0, nao_bipartidas = 0;
    for(int i = 1; i <= vertices; i++) {
        if(visitado[i]) continue;
        int nos = 0;
        bool bp = dfs(i, 0, nos);
        if(nos == 1) isolados++;
        else if(bp) bipartidas++;
        else nao_bipartidas++;
    }
    
    ll resultado = 2LL * isolados * (vertices - isolados) + 1LL * isolados * isolados;
    resultado += 1LL * (bipartidas + nao_bipartidas) * (bipartidas + nao_bipartidas);
    resultado += 1LL * bipartidas * bipartidas;
    printf("%lld\n", resultado);
    return 0;
}

D - Refletor Semi-Transparente

Simulação com otimização. Reflexões invertem estados (A/B) e deslocam partículas. Após n operações, a configuração estabiliza em padrões alternados. Trata casos especiais para k grande usando paridade.

#include <cstdio>
#include <cctype>
using namespace std;

int ler() {
    int num = 0; char c = getchar();
    while(!isdigit(c)) c = getchar();
    while(isdigit(c)) num = num * 10 + (c - '0'), c = getchar();
    return num;
}

const int TAM = 400005;
int estados[TAM], comprimento, passos, pos;

int main() {
    comprimento = ler(), passos = ler();
    char c = getchar();
    while(c != 'A' && c != 'B') c = getchar();
    for(int i = 0; i < comprimento; i++) {
        estados[i] = (c == 'B') ? 1 : 0;
        c = getchar();
    }
    
    bool flip = false;
    pos = 0;
    int executados = 0;
    while(executados < passos && pos < comprimento) {
        if(estados[pos] ^ flip) {
            estados[pos] ^= 1;
            pos--;
            executados++;
        } else {
            flip ^= 1;
            estados[comprimento + pos] = flip;
            executados++;
            pos++;
        }
    }
    
    if(executados == passos) {
        for(int i = pos; i < pos + comprimento; i++) 
            putchar((estados[i] ^ flip) ? 'B' : 'A');
        return 0;
    }
    
    if(comprimento & 1) {
        putchar((passos - executados) & 1 ? 'B' : 'A');
        for(int i = 1; i < comprimento; i++) 
            putchar(i & 1 ? 'B' : 'A');
    } else {
        for(int i = 0; i < comprimento; i++) 
            putchar(i & 1 ? 'B' : 'A');
    }
    return 0;
}

E - Números Crescentes

Números crescentes são somas de repunits (111...1). Representando repunits como (10ᵗ-1)/9, busca-se o menor k tal que 9N+9k tenha soma de dígitos ≤ 9k. Incrementa k até satisfazer a condição.

#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

const int TAM = 500505;
int digitos[TAM], comprimento;

int main() {
    string entrada;
    cin >> entrada;
    comprimento = entrada.size();
    reverse(entrada.begin(), entrada.end());
    
    for(int i = 0; i < comprimento; i++) 
        digitos[i] = (entrada[i] - '0') * 9;
    
    int soma_digitos = 0;
    for(int i = 0; i < comprimento; i++) {
        if(digitos[i] > 9) {
            digitos[i+1] += digitos[i] / 10;
            digitos[i] %= 10;
            if(i == comprimento-1) comprimento++;
        }
        soma_digitos += digitos[i];
    }
    
    if(soma_digitos == 0) {
        cout << "1\n";
        return 0;
    }
    
    int tentativas = 1;
    while(true) {
        digitos[0] += 9;
        soma_digitos += 9;
        int idx = 0;
        while(digitos[idx] > 9) {
            soma_digitos -= 9;
            digitos[idx] -= 10;
            digitos[++idx]++;
            if(idx == comprimento) comprimento++;
        }
        if(soma_digitos <= tentativas * 9) {
            cout << tentativas << "\n";
            return 0;
        }
        tentativas++;
    }
}

F - Planejamento de Serviço de Trens

Programação dinâmica com otimização por árvore de segmentos. Define-se estados baseados em tempos modulares. Atualizações de intervalo registram custos mínimos. Considera restrições de viagens simultâneas em trilhos únicos.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll ler() {
    ll num = 0; char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') num = num * 10 + (c - '0'), c = getchar();
    return num;
}

const ll INF = 1e18;
const int MAX = 100005;
int n, tipo[MAX];
ll a[MAX], suf[MAX], periodo;

struct Seg {
    int cnt, esq[MAX<<7], dir[MAX<<7];
    bool marcado[MAX<<7];
    ll valor[MAX<<7];

    void inicializar() { cnt = 1; valor[0] = INF; }

    void propagar(int no, int l, int r) {
        if(marcado[no]) {
            int m = (l + r) >> 1;
            if(!esq[no]) esq[no] = ++cnt;
            if(!dir[no]) dir[no] = ++cnt;
            marcado[esq[no]] = marcado[dir[no]] = true;
            valor[esq[no]] = -m;
            valor[dir[no]] = -r;
            marcado[no] = false;
        }
    }

    void atualizar(int &no, int l, int r, int pos, ll v) {
        if(!no) { no = ++cnt; valor[no] = INF; }
        if(l == r) { valor[no] = min(valor[no], v - pos); return; }
        propagar(no, l, r);
        int m = (l + r) >> 1;
        if(pos <= m) atualizar(esq[no], l, m, pos, v);
        else atualizar(dir[no], m+1, r, pos, v);
        valor[no] = min(valor[esq[no]], valor[dir[no]]);
    }

    void limpar(int no, int l, int r, int L, int R) {
        if(!no || valor[no] >= INF) return;
        if(L <= l && r <= R && (marcado[no] || l == r)) {
            marcado[no] = false;
            valor[no] = INF;
            return;
        }
        propagar(no, l, r);
        int m = (l + r) >> 1;
        if(L <= m) limpar(esq[no], l, m, L, R);
        if(R > m) limpar(dir[no], m+1, r, L, R);
        valor[no] = min(esq[no] ? valor[esq[no]] : INF, dir[no] ? valor[dir[no]] : INF);
    }

    void marcar(int &no, int l, int r, int L, int R) {
        if(!no) no = ++cnt;
        if(L <= l && r <= R) {
            marcado[no] = true;
            valor[no] = -r;
            return;
        }
        int m = (l + r) >> 1;
        if(L <= m) marcar(esq[no], l, m, L, R);
        if(R > m) marcar(dir[no], m+1, r, L, R);
        valor[no] = min(esq[no] ? valor[esq[no]] : INF, dir[no] ? valor[dir[no]] : INF);
    }

    ll consultar(int no, int l, int r, int L, int R) {
        if(!no) return INF;
        if(marcado[no]) return -min(r, R);
        if(L <= l && r <= R) return valor[no];
        propagar(no, l, r);
        int m = (l + r) >> 1;
        ll res = INF;
        if(L <= m) res = min(res, consultar(esq[no], l, m, L, R));
        if(R > m) res = min(res, consultar(dir[no], m+1, r, L, R));
        return res;
    }

    ll resposta(int no, int l, int r) {
        if(!no) return INF;
        if(marcado[no]) return 0;
        if(l == r) return valor[no] + l;
        propagar(no, l, r);
        int m = (l + r) >> 1;
        return min(resposta(esq[no], l, m), resposta(dir[no], m+1, r));
    }
} arvore;

int main() {
    n = ler(), periodo = ler();
    ll total = 0;
    for(int i = 1; i <= n; i++) {
        a[i] = ler();
        tipo[i] = ler();
        total += 2 * a[i];
        if(tipo[i] == 1 && 2 * a[i] > periodo) {
            printf("-1");
            return 0;
        }
    }

    while(n > 0 && tipo[n] == 2) n--;
    if(n == 0) {
        printf("%lld", total);
        return 0;
    }

    for(int i = n; i >= 1; i--) 
        suf[i] = (suf[i+1] + 2 * a[i]) % periodo;

    int raiz = 1;
    arvore.inicializar();
    arvore.marcar(raiz, 0, periodo-1, 0, periodo - 2 * a[n] - 1);

    for(int i = n-1; i >= 1; i--) {
        ll L = (periodo * 3 - 2 * a[i] - 2 * a[i+1] - suf[i+2]) % periodo;
        ll R = (periodo * 2 - suf[i+2] - 2 * a[i+1]) % periodo;
        ll temp = R;
        ll res = min(
            arvore.consultar(raiz, 0, periodo-1, temp, periodo-1) + temp + periodo,
            arvore.consultar(raiz, 0, periodo-1, 0, temp) + temp
        );

        if(tipo[i] == 1) {
            if(L <= R) arvore.limpar(raiz, 0, periodo-1, L, R);
            else {
                arvore.limpar(raiz, 0, periodo-1, L, periodo-1);
                arvore.limpar(raiz, 0, periodo-1, 0, R);
            }
        }
        arvore.atualizar(raiz, 0, periodo-1, (periodo - suf[i+1]) % periodo, res);
    }
    printf("%lld", arvore.resposta(1, 0, periodo-1) + total);
    return 0;
}

Tags: algoritmo-guloso ordenacao soma-prefixa teoria-grafos grafo-bipartido

Publicado em 7-30 02:02