Concours AtCoder pour Débutants 382

A - Cookie Quotidien

Énoncé du problème : Étant donné une chaîne de caractères de longueur n, où '.' représente une cellule vide et '@' représente un cookie, on consomme un cookie par jour. Combien de cellules sont vides après d jours ?

Approche : Simulation directe.

Code :


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

int main() {
    int longueur, jours;
    string donnees;
    cin >> longueur >> jours >> donnees;
    int nb_cookies = 0;
    for (char symbole : donnees) {
        if (symbole == '@') nb_cookies++;
    }
    int consommes = min(jours, nb_cookies);
    int cellules_vides = longueur - nb_cookies + consommes;
    cout << cellules_vides << endl;
    return 0;
}

B - Cookie Quotidien 2

Énoncé du problème : Identique à A, mais on mange le cookie le plus à droite chaque jour. Afficher l'état final de la chaîne.

Approche : Siumlation par parcours inverse.

Code :


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

int main() {
    int taille, objectif;
    string sequence;
    cin >> taille >> objectif >> sequence;
    int mange = 0;
    for (int idx = taille - 1; idx >= 0; idx--) {
        if (sequence[idx] == '@') {
            sequence[idx] = '.';
            mange++;
            if (mange == objectif) {
                cout << sequence << endl;
                return 0;
            }
        }
    }
    cout << sequence << endl;
    return 0;
}

C - Sushi Tournant

Énoncé du problème : n sushis avec des valeurs b_i ; m personnes avec des seuils a_i. Les sushis passent sur un tapis roulant. Une personne i mange un sushi j si a_i ≥ b_j, sinon elle ne fait rien. Trouver pour chaque sushi quelle personne le mange, ou -1 si personne ne le mange.

Approche : Identifier les personnes effectives (séquence décroissante des seuils), trier les sushis par valeur décroissante, puis assigner par recherche binaire.

Code :


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

int rechercherSeuil(vector<pair<int, int>>& personnes, int valeur) {
    int gauche = 0, droite = personnes.size();
    while (gauche < droite) {
        int milieu = gauche + (droite - gauche) / 2;
        if (personnes[milieu].first >= valeur) {
            gauche = milieu + 1;
        } else {
            droite = milieu;
        }
    }
    return gauche;
}

int main() {
    int nb_sushis, nb_personnes;
    cin >> nb_sushis >> nb_personnes;
    vector<int> valeurs_sushi(nb_sushis);
    for (int i = 0; i < nb_sushis; i++) {
        cin >> valeurs_sushi[i];
    }
    vector<pair<int, int>> personnes_effectives;
    int minimum = valeurs_sushi[0];
    personnes_effectives.push_back({valeurs_sushi[0], 1});
    for (int i = 1; i < nb_sushis; i++) {
        if (valeurs_sushi[i] < minimum) {
            minimum = valeurs_sushi[i];
            personnes_effectives.push_back({valeurs_sushi[i], i + 1});
        }
    }
    vector<pair<int, int>> attentes(nb_personnes);
    for (int i = 0; i < nb_personnes; i++) {
        cin >> attentes[i].first;
        attentes[i].second = i;
    }
    sort(attentes.begin(), attentes.end(), greater<pair<int, int>>());
    vector<int> resultat(nb_personnes, -1);
    int position = 0;
    for (auto& p : personnes_effectives) {
        int seuil = p.first;
        int index_personne = p.second;
        int prochain = rechercherSeuil(attentes, seuil);
        for (int j = position; j < prochain; j++) {
            resultat[attentes[j].second] = index_personne;
        }
        position = prochain;
    }
    for (int i = 0; i < nb_personnes; i++) {
        cout << resultat[i] << endl;
    }
    return 0;
}

D - Maintenir la Distance

Énoncé du problème : Étant donné n (n ≤ 12) et m (10×n-9 ≤ m ≤ 10×m), afficher dans l'ordre lexicographique toutes les séquences A de longueur n telles que A_{i-1} + 10 ≤ A_i et 1 ≤ A_i ≤ m.

Approche : Recherche en profondeur avec élagage basé sur la contrainte de distance.

Code :


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

int limite, longueur_seq;
vector<int> courante;
vector<vector<int>> solutions;

void explorer(int valeur) {
    if (courante.size() == longueur_seq) {
        solutions.push_back(courante);
        return;
    }
    for (int prochain = valeur + 10; prochain + (longueur_seq - courante.size() - 1) * 10 <= limite; prochain++) {
        courante.push_back(prochain);
        explorer(prochain);
        courante.pop_back();
    }
}

int main() {
    cin >> longueur_seq >> limite;
    for (int depart = 1; depart <= 10; depart++) {
        courante.push_back(depart);
        explorer(depart);
        courante.pop_back();
    }
    cout << solutions.size() << endl;
    for (auto& seq : solutions) {
        for (size_t i = 0; i < seq.size(); i++) {
            cout << seq[i];
            if (i < seq.size() - 1) cout << " ";
        }
        cout << endl;
    }
    return 0;
}

E - Paquets d'Expansion

Énoncé du problème : Un paquet de cartes contient n cartes, la i-ème carte a une probabilité p% d'être rare. Les tirages sont indépendants. Calculer l'espérance du nombre de paquets à ouvrir pour obtenir au moins x cartes rares.

Approche : Programmation dynamique pour calculer les probabilités et utiliser la formule de l'espérance conditionnelle.

Code :


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

const int MAXN = 5005;
double prob[MAXN][MAXN];
double esperance[MAXN];

int main() {
    int n, x;
    cin >> n >> x;
    vector<double> probabilites(n + 1);
    for (int i = 1; i <= n; i++) {
        int pourcentage;
        cin >> pourcentage;
        probabilites[i] = pourcentage * 1.0 / 100;
    }
    prob[0][0] = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= n; j++) {
            prob[i][j] = prob[i - 1][j] * (1 - probabilites[i]);
            if (j > 0) {
                prob[i][j] += prob[i - 1][j - 1] * probabilites[i];
            }
        }
    }
    for (int objectif = 1; objectif <= x; objectif++) {
        double somme = 0;
        double denominateur = 1 - prob[n][0];
        for (int k = 1; k < n; k++) {
            if (k < objectif) {
                somme += prob[n][k] * esperance[objectif - k];
            }
        }
        esperance[objectif] = (somme + 1) / denominateur;
    }
    cout << fixed << setprecision(12) << esperance[x] << endl;
    return 0;
}

Étiquettes: atcoder-contest simulation greedy-algorithm binary-search depth-first-search

Publié le 24 juin à 20h12