Solutions rapides pour le concours éducatif Codeforces 157 (Division 2)

Problème A – Déplacement optimal sur une ligne

On dispose d’un point situé en x et d’une cible en y. À chaque seconde on peut avancer d’au plus k unités. Le coût est simplement la position finale. Si x ≥ y, on atteint déjà la cible ; sinon on avance jusqu’à min(y, x+k) puis on rebrousse chemin pour atteindre y. Le temps total est donc y + (y - min(y, x+k)).

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

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;  cin >> t;
    while (t--) {
        long long x, y, k;
        cin >> x >> y >> k;
        if (x >= y) cout << x << '\n';
        else        cout << y + max(0LL, y - (x + k)) << '\n';
    }
}

Problème B – Partition d’un tableau en deux sous-séquences équilibrées

Étant donné 2n entiers, on veut les répartir en deux groupes de taille n de façon à minimiser la somme des écarts absolus entre éléments consécutifs dans chaque groupe. Il suffit de trier le tableau et de prendre les n plus petits dans un groupe et les n plus grands dans l’autre ; la preuve repose sur l’inégalité des réarrangements.

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

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int tc;  cin >> tc;
    while (tc--) {
        int n;  cin >> n;
        vector<int> v(2 * n);
        for (int &x : v) cin >> x;
        sort(v.begin(), v.end());

        long long cost = 0;
        for (int i = 1; i < n; ++i) cost += v[i] - v[i - 1];
        for (int i = n + 1; i < 2 * n; ++i) cost += v[i] - v[i - 1];
        cout << cost << '\n';
        for (int i = 0; i < n; ++i)
            cout << v[i] << " \n"[i == n - 1];
        for (int i = 0; i < n; ++i)
            cout << v[i + n] << " \n"[i == n - 1];
    }
}

Problème C – Appariements de chaînes numériques équilibrées

Une chaîne est « équilibrée » si, une fois coupée en deux parties de même longueur, la somme des chiffres de la première moitié égale celle de la seconde. Étant donné n chaînes, on compte les paires (i, j) (l’ordre compte, i = j autorisé) telles que la concaténation s<sub>i</sub> + s<sub>j</sub> soit équilibrée.

On remarque que seules la longueur et la somme des chiffres d’une chaîne importe. On maintient un tableau freq[len][sum] et on parcourt chaque chaîne pour déterminer avec quelles longueurs complémentaires elle peut s’apparier.

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

int freq[10][500];          // len <= 5, sum <= 9*5

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;  cin >> n;
    vector<string> s(n);
    vector<int> sum(n);

    for (int i = 0; i < n; ++i) {
        cin >> s[i];
        int cur = 0;
        for (char c : s[i]) cur += c - '0';
        sum[i] = cur;
        ++freq[(int)s[i].size()][cur];
    }

    long long total = 0;
    for (int i = 0; i < n; ++i) {
        int len = (int)s[i].size();
        int pref = 0;
        for (int cut = 1; cut < len; ++cut) {
            pref += s[i][cut - 1] - '0';
            int need = 2 * pref - sum[i];
            int other = 2 * cut - len;
            if (other > 0 && other <= 5)
                total += freq[other][need];
        }
        pref = 0;
        for (int cut = len - 1; cut > 0; --cut) {
            pref += s[i][cut] - '0';
            int need = 2 * pref - sum[i];
            int other = len - 2 * cut;
            if (other > 0 && other <= 5)
                total += freq[other][need];
        }
    }
    cout << total + n << '\n';
}

Problème D – Reconstruction d’un tableau à partir de XOR adjacents

On connaît a<sub>1</sub>, …, a<sub>n-1</sub> avec a<sub>i</sub> = b<sub>i</sub> XOR b<sub>i+1</sub>. Il faut produire b<sub>1</sub>, …, b<sub>n</sub> distincts et compris entre 0 et n-1.

En posant s<sub>k</sub> = a<sub>1</sub> XOR … XOR a<sub>k</sub>, on obtient b<sub>k+1</sub> = s<sub>k</sub> XOR b<sub>1</sub>. Reste à choisir b<sub>1</sub> tel que l’ensemble {b<sub>1</sub>, s<sub>1</sub> XOR b<sub>1</sub>, …} soit exactement {0, 1, …, n-1}. On utilise un Trie binaire pour tester rapidement, en O(log n) par candidat, si le maximum obtenu reste inférieur à n.

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

const int LG = 20;
struct Trie {
    int ch[2]{}, cnt = 0;
} tr[LG * 200000];
int nodes = 1;

void insert(int x) {
    int cur = 0;
    for (int b = LG - 1; b >= 0; --b) {
        int bit = (x >> b) & 1;
        if (!tr[cur].ch[bit]) tr[cur].ch[bit] = nodes++;
        cur = tr[cur].ch[bit];
    }
}

int max_xor(int x) {
    int cur = 0, res = 0;
    for (int b = LG - 1; b >= 0; --b) {
        int bit = (x >> b) & 1;
        if (tr[cur].ch[!bit]) {
            res |= 1 << b;
            cur = tr[cur].ch[!bit];
        } else {
            cur = tr[cur].ch[bit];
        }
    }
    return res;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;  cin >> n;
    vector<int> a(n - 1);
    for (int &x : a) cin >> x;

    vector<int> pref(n);
    for (int i = 1; i < n; ++i) pref[i] = pref[i - 1] ^ a[i - 1];
    for (int v : pref) insert(v);

    int b0 = 0;
    for (int cand = 0; cand < n; ++cand)
        if (max_xor(cand) < n) { b0 = cand; break; }

    cout << b0;
    for (int i = 1; i < n; ++i) cout << ' ' << (b0 ^ pref[i]);
    cout << '\n';
}

Étiquettes: codeforces Greedy sorting hash-map Trie

Publié le 11 septembre à 15h17