Resolução de Problemas da PTA – Conjunto 1 (C++)

Problema 1 – Caracteres distintos
Problema 2 – Comparação de bits
Problema 3 – K-ésimo menor distinto
Problema 4 – Desarranjos
Problema 5 – Tempo de espera
Problema 6 – Ponto crítico (Union-Find)
Problema 7 – Conectividade em grade
Problema 8 – Mediana das cooordenadas
Problema 9 – Soma dos divisores
Problema 10 – Caminho crescente mais longo

Problema 1 – Caracteres distintos

Problema 1

Código reformulado:

#include <iostream>
#include <unordered_set>
#include <string>

using namespace std;

int main() {
    string entrada;
    getline(cin, entrada);                     // lê a string completa
    
    unordered_set<char> caracteres(entrada.begin(), entrada.end()); // extrai caracteres únicos
    
    if (caracteres.size() % 2 == 1)            // quantidade ímpar?
        cout << "IGNORE HIM!" << endl;
    else
        cout << "CHAT WITH HER!" << endl;
            
    return 0;
}

Problema 2 – Comparação de bits

Problema 2

Código reformulado:

#include <iostream>
#include <bitset>

using namespace std;

int main() {
    int a, b;
    cin >> a >> b;
    
    int popA = bitset<32>(a).count();
    int popB = bitset<32>(b).count();
    
    if (popA > popB)
        cout << a;
    else if (popB > popA)
        cout << b;
    else
        cout << max(a, b);
    
    return 0;
}

Problema 3 – K-ésimo menor distnito

Problema 3

Código reformulado:

#include <iostream>
#include <set>
#include <vector>

using namespace std;

int main() {
    int n, k;
    cin >> n >> k;
    
    set<int> valores;                         // armazena apenas elementos distintos
    for (int i = 0; i < n; ++i) {
        int x;
        cin >> x;
        valores.insert(x);
    }
    
    if (k <= valores.size()) {
        auto it = valores.begin();
        advance(it, k-1);                     // k-ésimo (índice 0)
        cout << *it << endl;
    } else {
        cout << "NO RESULT" << endl;
    }
    
    return 0;
}

Problema 4 – Desarranjos

Problema 4

Código reformulado (usando recorrrência):

#include <iostream>
#include <vector>

using namespace std;

int main() {
    int testes;
    cin >> testes;
    
    while (testes--) {
        int n;
        cin >> n;
        
        if (n <= 8) {                         // n pequeno: recorrência exata
            long long d0 = 1, d1 = 0;         // D(0)=1, D(1)=0
            for (int i = 2; i <= n; ++i) {
                long long di = (i-1) * (d0 + d1);
                d0 = d1;
                d1 = di;
            }
            long long total = 1;              // n!
            for (int i = 2; i <= n; ++i) total *= i;
            double probabilidade = (double) d1 / total * 100.0;
            printf("%.2lf%%\n", probabilidade);
        } else {
            cout << "36.79%" << endl;
        }
    }
    return 0;
}

Problema 5 – Tempo de espera

Problema 5

Código reformulado:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Ticket {
    int tempo;
    int id;
};

int main() {
    int n;
    cin >> n;
    vector<Ticket> pessoas(n);
    for (int i = 0; i < n; ++i) {
        cin >> pessoas[i].tempo;
        pessoas[i].id = i+1;
    }
    
    // ordena pelo tempo (menor primeiro)
    sort(pessoas.begin(), pessoas.end(), [](const Ticket &a, const Ticket &b) {
        return a.tempo < b.tempo;
    });
    
    long long somaEspera = 0;
    for (int i = 0; i < n; ++i) {
        somaEspera += (n - i) * pessoas[i].tempo;  // (n-i) pessoas esperam esse tempo
        cout << pessoas[i].id;
        if (i != n-1) cout << " ";
    }
    cout << endl;
    
    double media = somaEspera / (double) n;
    printf("%.2lf\n", media);
    
    return 0;
}

Problema 6 – Ponto crítico (Union-Find reverso)

Problema 6

Código reformulado:

#include <iostream>
#include <vector>

using namespace std;

struct DSU {
    vector<int> pai, tamanho;
    DSU(int n) {
        pai.resize(n+1);
        tamanho.assign(n+1, 1);
        for (int i = 1; i <= n; ++i) pai[i] = i;
    }
    int find(int x) {
        return pai[x] == x ? x : pai[x] = find(pai[x]);
    }
    void merge(int a, int b) {
        a = find(a); b = find(b);
        if (a != b) {
            pai[a] = b;
            tamanho[b] += tamanho[a];
        }
    }
    int getTamanho(int x) {
        return tamanho[find(x)];
    }
};

int main() {
    int n;
    cin >> n;
    
    vector<vector<int>> grafo(n+1);
    for (int i = 1; i <= n; ++i) {
        int k; cin >> k;
        grafo[i].resize(k);
        for (int j = 0; j < k; ++j) cin >> grafo[i][j];
    }
    
    DSU dsu(n);
    // Processa de n até 1 (ordem reversa)
    for (int v = n; v >= 1; --v) {
        for (int u : grafo[v]) {
            if (u > v) {                    // só conecta com vértices maiores
                dsu.merge(v, u);
            }
            if (dsu.getTamanho(v) > n/2) {
                cout << v << endl;
                return 0;
            }
        }
    }
    
    return 0;
}

Problema 7 – Conectividade em grade

Problema 7

Código reformulado:

#include <iostream>
#include <vector>
#include <set>

using namespace std;

struct UnionFind {
    vector<int> pai;
    UnionFind(int n) : pai(n+1) {
        for (int i = 1; i <= n; ++i) pai[i] = i;
    }
    int find(int x) {
        return pai[x] == x ? x : pai[x] = find(pai[x]);
    }
    void merge(int a, int b) {
        a = find(a); b = find(b);
        if (a != b) pai[a] = b;
    }
};

inline int id(int linha, int col, int m) {
    return (linha-1) * m + col;
}

int main() {
    int n, m;
    cin >> n >> m;
    
    UnionFind uf(n*m);
    set<int> colunasProcessadas;               // colunas que já receberam horizontal
    
    // Leitura das ligações verticais
    int a1, a2, b1, b2;
    while (cin >> a1 >> a2 >> b1 >> b2) {
        if (a2 != b2)                          // ligação horizontal entre colunas
            colunasProcessadas.insert(min(a2, b2));
        int u = id(a1, a2, m);
        int v = id(b1, b2, m);
        uf.merge(u, v);
    }
    
    long long resposta = 0;
    // Adiciona arestas horizontais ausentes (cada uma custa 2)
    for (int c = 1; c < m; ++c) {
        if (!colunasProcessadas.count(c)) {
            resposta += 2;
            uf.merge(id(1, c, m), id(1, c+1, m));
        }
    }
    
    // Conta componentes conexas
    set<int> componentes;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            componentes.insert(uf.find(id(i, j, m)));
        }
    }
    resposta += componentes.size() - 1;       // arestas verticais necessárias
    
    cout << resposta << endl;
    
    return 0;
}

Problema 8 – Mediana das coordenadas

Problema 8

Código reformulado:

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>

using namespace std;

int main() {
    int n;
    cin >> n;
    
    vector<int> coords(n);
    for (int i = 0; i < n; ++i) {
        int x;
        cin >> x >> coords[i];          // x descartado, y armazenado
    }
    
    // nth_element coloca o k-ésimo menor na posição k (0‑based)
    nth_element(coords.begin(), coords.begin() + n/2, coords.end());
    int mediana = coords[n/2];
    
    long long soma = 0;
    for (int y : coords) {
        soma += abs(y - mediana);
    }
    
    cout << " " << soma << endl;        // mantém o espaço inicial do output original
    
    return 0;
}

Problema 9 – Soma dos divisores

Problema 9

Código reformulado:

#include <iostream>

using namespace std;

int main() {
    long long n;
    cin >> n;
    
    long long total = 0;
    for (long long i = 1; i <= n; ++i) {
        total += n / i;                    // quantidade de múltiplos de i entre 1 e n
    }
    
    cout << total << endl;
    
    return 0;
}

Problema 10 – Caminho crescente mais longo

Problema 10

Problema 10 (cont.)

Código reformulado:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, 1, -1};

int dfs(int x, int y, const vector<vector<int>>& mat, vector<vector<int>>& memo) {
    if (memo[x][y] != 0) return memo[x][y];
    
    int melhor = 1;
    for (int dir = 0; dir < 4; ++dir) {
        int nx = x + dx[dir];
        int ny = y + dy[dir];
        if (nx >= 0 && nx < mat.size() && ny >= 0 && ny < mat[0].size() && mat[nx][ny] > mat[x][y]) {
            melhor = max(melhor, 1 + dfs(nx, ny, mat, memo));
        }
    }
    return memo[x][y] = melhor;
}

int main() {
    int n, m;
    cin >> n >> m;
    
    vector<vector<int>> grade(n, vector<int>(m));
    for (auto& linha : grade)
        for (int& valor : linha)
            cin >> valor;
    
    vector<vector<int>> memoria(n, vector<int>(m, 0));
    int maiorCaminho = 0;
    
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < m; ++j)
            maiorCaminho = max(maiorCaminho, dfs(i, j, grade, memoria));
    
    cout << maiorCaminho << endl;
    
    return 0;
}

Tags: C++ PTA Algoritmos Union-Find dfs

Publicado em 6-11 05:47 por Thomas