Análise dos Problemas do AtCoder Beginner Contest 371

Análise dos Prbolemas do AtCoder Beginner Contest 371

Este artigo explora as soluções técnicas dos problemas do AtCoder Beginner Contest 371, com foco em algoritmos e estruturas de dados.

Problema A

O Problema A envolve determinar o segundo maior entre três indivíduos, A, B e C, com base em desigualdades fornecidas. A abordagem eficiente consiste em avaliar as condições de desigualdade para estabelecer a ordem de classificação.

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

int main() {
    char relAB, relAC, relBC;
    cin >> relAB >> relAC >> relBC;
    
    char persons[] = {'A', 'B', 'C'};
    int ranks[] = {1, 2, 3};
    
    do {
        int rankA = ranks[0], rankB = ranks[1], rankC = ranks[2];
        bool isValid = true;
        
        if (relAB == '<' && rankA >= rankB) isValid = false;
        if (relAB == '>' && rankA <= rankB) isValid = false;
        if (relAC == '<' && rankA >= rankC) isValid = false;
        if (relAC == '>' && rankA <= rankC) isValid = false;
        if (relBC == '<' && rankB >= rankC) isValid = false;
        if (relBC == '>' && rankB <= rankC) isValid = false;
        
        if (isValid) {
            for (int i = 0; i < 3; i++) {
                if (ranks[i] == 2) {
                    cout << persons[i] << endl;
                    return 0;
                }
            }
        }
    } while (next_permutation(ranks, ranks+3));
    
    return 0;
}

Problema B

No Problema B, é necessário registrar o filho mais velho durante consultas e verificar correspondências. A solução armazena informações em arrays e realiza comparações diretas.

#include <iostream>
using namespace std;

const int MAX_ENTRIES = 105;
int numNodes, numQueries;
int queryIDs[MAX_ENTRIES];
int eldestChild[MAX_ENTRIES];

int main() {
    cin >> numNodes >> numQueries;
    for (int i = 1; i <= numQueries; i++) {
        int nodeID;
        char queryType;
        cin >> nodeID >> queryType;
        queryIDs[i] = nodeID;
        if (queryType == 'F') continue;
        if (eldestChild[nodeID] == 0) eldestChild[nodeID] = i;
    }
    for (int i = 1; i <= numQueries; i++) {
        if (eldestChild[queryIDs[i]] == i) cout << "Yes\n";
        else cout << "No\n";
    }
    return 0;
}

Problema C

O Problema C possui um tamanho n pequeno, permitindo a enumeração de todas as permutações de p para calcular o custo mínimo. A consideração de arestas bidirecionais é crucial para a solução.

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

const int MAX_SIZE = 10;
int n, mFirst, mSecond;
int permutation[MAX_SIZE];
int graphFirst[MAX_SIZE][MAX_SIZE], graphSecond[MAX_SIZE][MAX_SIZE], edgeCost[MAX_SIZE][MAX_SIZE];
int minCost = 0x3f3f3f3f;

int main() {
    cin >> n;
    cin >> mFirst;
    for (int i = 0; i < mFirst; i++) {
        int u, v;
        cin >> u >> v;
        graphFirst[u][v] = graphFirst[v][u] = 1;
    }
    cin >> mSecond;
    for (int i = 0; i < mSecond; i++) {
        int u, v;
        cin >> u >> v;
        graphSecond[u][v] = graphSecond[v][u] = 1;
    }
    for (int i = 1; i <= n; i++)
        for (int j = i+1; j <= n; j++)
            cin >> edgeCost[i][j], edgeCost[j][i] = edgeCost[i][j];
    
    for (int i = 1; i <= n; i++) permutation[i] = i;
    do {
        int currentCost = 0;
        for (int i = 1; i <= n; i++)
            for (int j = i+1; j <= n; j++) {
                int mappedI = permutation[i], mappedJ = permutation[j];
                if (graphFirst[i][j] != graphSecond[mappedI][mappedJ]) currentCost += edgeCost[mappedI][mappedJ];
            }
        minCost = min(minCost, currentCost);
    } while (next_permutation(permutation+1, permutation+n+1));
    
    cout << minCost << endl;
    return 0;
}

Problema D

O Problema D utiliza discretização e soma de prefixos para processar consultas de intervalo de maneira eficiente, transformando coordenadas em índices contínuos.

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

typedef long long ll;
const int MAX_QUERIES = 1e6 + 5;
int n, q;
vector<int> pointPositions;
vector<ll> pointValues;
vector<ll> prefixSums;

int main() {
    cin >> n;
    for (int i = 0; i < n; i++) {
        int pos;
        cin >> pos;
        pointPositions.push_back(pos);
    }
    for (int i = 0; i < n; i++) {
        ll val;
        cin >> val;
        pointValues.push_back(val);
    }
    
    vector<int> allPoints = pointPositions;
    cin >> q;
    vector<pair<int, int>> queryList(q);
    for (int i = 0; i < q; i++) {
        cin >> queryList[i].first >> queryList[i].second;
        allPoints.push_back(queryList[i].first);
        allPoints.push_back(queryList[i].second);
    }
    sort(allPoints.begin(), allPoints.end());
    allPoints.erase(unique(allPoints.begin(), allPoints.end()), allPoints.end());
    
    int totalPoints = allPoints.size();
    prefixSums.resize(totalPoints+1, 0);
    for (int i = 0; i < n; i++) {
        int idx = lower_bound(allPoints.begin(), allPoints.end(), pointPositions[i]) - allPoints.begin();
        prefixSums[idx+1] += pointValues[i];
    }
    for (int i = 1; i <= totalPoints; i++) prefixSums[i] += prefixSums[i-1];
    
    for (auto &query : queryList) {
        int leftIdx = lower_bound(allPoints.begin(), allPoints.end(), query.first) - allPoints.begin();
        int rightIdx = lower_bound(allPoints.begin(), allPoints.end(), query.second) - allPoints.begin();
        cout << prefixSums[rightIdx+1] - prefixSums[leftIdx] << endl;
    }
    return 0;
}

Problema E

O Problema E emprega soma de prefixos e rastreamento de ocorrências futuras para calcular a contribuição total de todas as subsequências de forma otimizada, evitando complexidade quadrática.

#include <iostream>
#include <vector>
using namespace std;

typedef long long ll;
const int MAX_N = 2e5 + 5;
int n;
int sequence[MAX_N];
vector<int> occurrenceList[MAX_N];
int nextOccurIndex[MAX_N];
ll accumulatedSum, finalAnswer;

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> sequence[i];
        occurrenceList[sequence[i]].push_back(i);
    }
    
    for (int i = 1; i <= n; i++) occurrenceList[i].push_back(n+1);
    
    ll currentSum = 0;
    int distinctCount = 0;
    for (int i = 1; i <= n; i++) {
        if (occurrenceList[sequence[i]][nextOccurIndex[sequence[i]]] == i) distinctCount++;
        currentSum += distinctCount;
    }
    
    finalAnswer = currentSum;
    for (int i = 1; i < n; i++) {
        int nextOccur = occurrenceList[sequence[i]][++nextOccurIndex[sequence[i]]];
        currentSum -= (nextOccur - i);
        finalAnswer += currentSum;
    }
    
    cout << finalAnswer << endl;
    return 0;
}

Tags: AtCoder C++ Algoritmos Programação Competitiva permutações

Publicado em 6-8 01:14 por Thomas