Разбор квалификационного тура**Qualification Round Editorial**
Difference between ru1 and en1, changed 16187 character(s)
### A. Очередь на пуфболQueue for Puffball↵
↵
**Idea:** [user:Arbuzik342,2026-10-04]↵
**Preparation:** [user:Arbuzik342,2026-10-04], [user:zeyd1234,2026-10-04]↵
↵
<spoiler summary="
Подсказка 1">↵
Посчитайте для каждой семьи две величины: сколько её представителей в очереди и на какой позиции стоит самый первый.↵
</spoiler>↵
↵
<spoiler summary="Подсказка 2">↵
Сортировка семей двухуровневая: сначала по количеству (по убыванию), при равенстве — по позиции первого представителя (по возрастанию).↵
</spoiler>↵
↵
<spoiler summary="Решение">↵
Попробуйте завести два массива: `amount[x]` — число людей из семьи `x` и `firstTime[x]` — минимальный индекс, на котором встречается семья `x`. Пройдите по входу один раз и заполните оба. Затем сложите все уникальные номера семей в вектор и отсортируйте их компаратором
Hint 1">↵
For each family, compute two values: how many of its members are in the queue, and the position of the earliest one.↵
</spoiler>↵
↵
<spoiler summary="Hint 2">↵
The sorting of families is two-level: first by count (descending), and on ties — by the position of the earliest member (ascending).↵
</spoiler>↵
↵
<spoiler summary="Solution">↵
Try to maintain two arrays: `amount[x]` — the number of people from family `x`, and `firstTime[x]` — the smallest index at which family `x` appears. Go through the input once and fill in both. Then collect all distinct family IDs into a vector and sort them with the comparator
:↵
↵
```cpp↵
if (amount[a] != amount[b]) return amount[a] > amount[b];↵
return firstTime[a] < firstTime[b];↵
```↵
↵
Осталось вывести каждую семью столько раз, сколько у неё людей. СложностьAll that's left is to print each family as many times as it has people. Complexity — `O(n log n)`.↵
</spoiler>↵
↵
<spoiler summary="
КодCode">↵
```cpp↵
#include <bits/stdc++.h>↵
using namespace std;↵
↵
int main() {↵
    ios::sync_with_stdio(false);↵
    cin.tie(nullptr);↵
    int n, m;↵
    cin >> n >> m;↵
    vector<int> people(n);↵
    vector<int> amount(m + 1, 0), firstTime(m + 1, -1);↵
    for (int i = 0; i < n; i++) {↵
        cin >> people[i];↵
        amount[people[i]]++;↵
        if (firstTime[people[i]] == -1) {↵
            firstTime[people[i]] = i;↵
        }↵
    }↵
    vector<int> uniqueFamilies;↵
    for (int x = 1; x <= m; x++) {↵
        if (amount[x] > 0) {↵
            uniqueFamilies.push_back(x);↵
        }↵
    }↵
    sort(uniqueFamilies.begin(), uniqueFamilies.end(),↵
         [&](int a, int b) {↵
             if (amount[a] != amount[b]) {↵
                 return amount[a] > amount[b];↵
             }↵
             return firstTime[a] < firstTime[b];↵
         });↵
    for (int fam : uniqueFamilies) {↵
        for (int k = 0; k < amount[fam]; k++) {↵
            cout << fam << ' ';↵
        }↵
    }↵
    cout << '\n';↵
    return 0;↵
}↵
```↵
</spoiler>↵
↵
---↵
↵
### B. 
Без лишних сравненийNo Extra Comparisons↵
↵
**Idea:** [user:Arbuzik342,2026-10-04]↵
**Preparation:** [user:Arbuzik342,2026-10-04], [user:zeyd1234,2026-10-04]↵
↵
<spoiler summary="
Подсказка 1">↵
Это обычный пузырёк с оптимизацией: после каждого прохода правая часть массива уже отсортирована.↵
</spoiler>↵
↵
<spoiler summary="Подсказка 2">↵
Границей следующего прохода служит индекс последнего обмена в текущем проходе. Если обменов не было — сортировка завершена.↵
</spoiler>↵
↵
<spoiler summary="Решение">↵
Промоделируйте процесс. Пусть `limit` — количество пар для просмотра в текущем проходе. Изначально `limit = n - 1`. На каждом проходе пробегайте
Hint 1">↵
This is the ordinary bubble sort with an optimization: after each pass, the right part of the array is already sorted.↵
</spoiler>↵
↵
<spoiler summary="Hint 2">↵
The bound of the next pass is the index of the last swap in the current pass. If there were no swaps — the sorting is done.↵
</spoiler>↵
↵
<spoiler summary="Solution">↵
Simulate the process. Let `limit` be the number of pairs to consider in the current pass. Initially `limit = n - 1`. On each pass, iterate
 `i` отfrom `0` доto `limit - 1`, увеличивайте счётчик секунд, при необходимости меняйте местамиincrement the seconds counter, and if needed swap `a[i]` иand `a[i+1]` и запоминайте, remembering `lastSwap = i`. После прохода, еслиAfter the pass, if `lastSwap == -1`, выходите. Иначеstop. Otherwise `limit = lastSwap`.↵
↵
СложностьComplexity — `O(n²)` в худшем случае, но при `n ≤ 1000` этого достаточноin the worst case, but with `n ≤ 1000` this is more than enough.↵
</spoiler>↵
↵
<spoiler summary="
КодCode">↵
```cpp↵
#include <bits/stdc++.h>↵
using namespace std;↵
↵
int main() {↵
    ios::sync_with_stdio(false);↵
    cin.tie(nullptr);↵
    int n;↵
    cin >> n;↵
    vector<int> a(n);↵
    for (int i = 0; i < n; i++) {↵
        cin >> a[i];↵
    }↵
    long long totalSeconds = 0;↵
    int limit = n - 1;↵
    while (limit > 0) {↵
        int lastSwap = -1;↵
        for (int i = 0; i < limit; i++) {↵
            totalSeconds++;↵
            if (a[i] > a[i + 1]) {↵
                swap(a[i], a[i + 1]);↵
                lastSwap = i;↵
            }↵
        }↵
        if (lastSwap == -1) {↵
            break;↵
        }↵
        limit = lastSwap;↵
    }↵
    cout << totalSeconds << '\n';↵
    return 0;↵
}↵
```↵
</spoiler>↵
↵
---↵
↵
### C. 
Вспомни алфавитRemember the Alphabet↵
↵
**Idea:** [user:Arbuzik342,2026-10-04]↵
**Preparation:** [user:Arbuzik342,2026-10-04], [user:zeyd1234,2026-10-04]↵
↵
<spoiler summary="
Подсказка 1">↵
Алфавит — линейная цепочка: у каждой буквы максимум один «следующий» и максимум один «предыдущий».↵
</spoiler>↵
↵
<spoiler summary="Подсказка 2">↵
Проверьте три вещи: нет развилок, нет слияний, обход от начала цепочки покрывает все встречающиеся буквы и не натыкается на цикл.↵
</spoiler>↵
↵
<spoiler summary="Решение">↵
Постройте ориентированный граф на 26 буквах. Для каждой пары `(X, Y)` проверьте: у `X` ещё нет исходящего ребра в другую букву; у `Y` ещё нет входящего ребра из другой буквы. Иначе — `NO`. После добавления всех рёбер найдите единственную букву с `in-degree = 0` и пройдите по цепочке, помечая посещённые. Если наткнулись на уже посещённую букву — цикл. Если длина обхода меньше общего числа встречающихся букв — потерялась компонента. В обоих случаях
Hint 1">↵
The alphabet is a linear chain: each letter has at most one "next" and at most one "previous".↵
</spoiler>↵
↵
<spoiler summary="Hint 2">↵
Check three things: no forks, no merges, and the traversal from the start of the chain covers every letter that appears and doesn't run into a cycle.↵
</spoiler>↵
↵
<spoiler summary="Solution">↵
Build a directed graph on 26 letters. For each pair `(X, Y)`, check: `X` doesn't already have an outgoing edge to another letter; `Y` doesn't already have an incoming edge from another letter. Otherwise — `NO`. After adding all edges, find the only letter with `in-degree = 0` and walk along the chain, marking visited letters. If you hit a visited letter — a cycle. If the traversal length is less than the total number of letters that appear — a component is missing. In both cases,
 `NO`.↵
</spoiler>↵
↵
<spoiler summary="
КодCode">↵
```cpp↵
#include <bits/stdc++.h>↵
using namespace std;↵
↵
int main() {↵
    ios::sync_with_stdio(false);↵
    cin.tie(nullptr);↵
    int n;↵
    cin >> n;↵
    vector<int> nextLetter(26, -1), prevLetter(26, -1);↵
    vector<int> appears(26, 0);↵
    for (int i = 0; i < n; i++) {↵
        char x, y;↵
        cin >> x >> y;↵
        int a = x - 'A', b = y - 'A';↵
        appears[a] = appears[b] = 1;↵
        if (nextLetter[a] != -1 && nextLetter[a] != b) {↵
            cout << "NO\n";↵
            return 0;↵
        }↵
        if (prevLetter[b] != -1 && prevLetter[b] != a) {↵
            cout << "NO\n";↵
            return 0;↵
        }↵
        nextLetter[a] = b;↵
        prevLetter[b] = a;↵
    }↵
    int start = -1;↵
    for (int i = 0; i < 26; i++) {↵
        if (appears[i] && prevLetter[i] == -1) {↵
            if (start != -1) {↵
                cout << "NO\n";↵
                return 0;↵
            }↵
            start = i;↵
        }↵
    }↵
    if (start == -1) {↵
        cout << "NO\n";↵
        return 0;↵
    }↵
    vector<int> visited(26, 0);↵
    string result;↵
    int cur = start;↵
    while (cur != -1) {↵
        if (visited[cur]) {↵
            cout << "NO\n";↵
            return 0;↵
        }↵
        visited[cur] = 1;↵
        result += char('A' + cur);↵
        cur = nextLetter[cur];↵
    }↵
    int totalUsed = 0;↵
    for (int i = 0; i < 26; i++) {↵
        totalUsed += appears[i];↵
    }↵
    if ((int)result.size() != totalUsed) {↵
        cout << "NO\n";↵
        return 0;↵
    }↵
    cout << result << '\n';↵
    return 0;↵
}↵
```↵
</spoiler>↵
↵
---↵
↵
### D. 
Открой кейсы выгодноOpening Cases Is Profitable↵
↵
**Idea:** [user:Arbuzik342,2026-10-04]↵
**Preparation:** [user:Arbuzik342,2026-10-04], [user:zeyd1234,2026-10-04]↵
↵
<spoiler summary="
Подсказка 1">↵
Рассмотрите задачу как DP по префиксу: `best[i]` — лучший ответ для первых `i` кейсов
Hint 1">↵
Treat the problem as a prefix DP: `best[i]` — the best answer for the first `i` cases
.↵
</spoiler>↵
↵
<spoiler summary="
Подсказка 2">↵
Если открыть `i`-й кейс, следующие `m` пропускаются. Переход
Hint 2">↵
If you open case `i`, the next `m` are skipped. Transition
: `best[i] = max(best[i-1], value[i] + best[i-m-1])`.↵
</spoiler>↵
↵
<spoiler summary="
Решение">↵
Классическая задача о «взять или пропустить с блокировкой». Попробуйте вести `best[i]` — максимальная сумма на префиксе длины `i`. Для каждого `i`: либо не берём `i`-й кейс (`best[i-1]`), либо берём его и перескакиваем `m` следующих
Solution">↵
This is the classic "take or skip with a cooldown" problem. Try to maintain `best[i]` — the maximum total value on a prefix of length `i`. For each `i`: either skip case `i` (`best[i-1]`), or take it and jump over `m` following
 (`value[i] + best[max(0, i-m-1)]`). Ответ — `best[n]`. Значения сумм могут достигатьThe answer is `best[n]`. The sums can reach `10^14`, нуженso `long long` is required.↵
</spoiler>↵
↵
<spoiler summary="
КодCode">↵
```cpp↵
#include <bits/stdc++.h>↵
using namespace std;↵
↵
int main() {↵
    ios::sync_with_stdio(false);↵
    cin.tie(nullptr);↵
    int n, m;↵
    cin >> n >> m;↵
    vector<long long> value(n + 1, 0), best(n + 1, 0);↵
    for (int i = 1; i <= n; i++) {↵
        cin >> value[i];↵
    }↵
    for (int i = 1; i <= n; i++) {↵
        int jumpBack = i - m - 1;↵
        if (jumpBack < 0) {↵
            jumpBack = 0;↵
        }↵
        best[i] = max(best[i - 1], value[i] + best[jumpBack]);↵
    }↵
    cout << best[n] << '\n';↵
    return 0;↵
}↵
```↵
</spoiler>↵
↵
---↵
↵
### E. 
Горы ФлатландииMountains of Flatland↵
↵
**Idea:** [user:Arbuzik342,2026-10-04]↵
**Preparation:** [user:Arbuzik342,2026-10-04], [user:zeyd1234,2026-10-04]↵
↵
<spoiler summary="
Подсказка 1">↵
В задаче `n · m ≤ 10^5`, значит можно спокойно пройтись по всей матрице один раз
Hint 1">↵
In this problem `n · m ≤ 10^5`, so you can safely traverse the entire matrix once
.↵
</spoiler>↵
↵
<spoiler summary="
Подсказка 2">↵
Для каждой высоты запомните ячейку с минимальным номером столбца, а при равенстве — с минимальным номером ряда.↵
</spoiler>↵
↵
<spoiler summary="Решение">↵
Пройдитесь по матрице и попробуйте завести `map<int, pair<int,int>>`, где ключ — высота, а значение — координаты `(row, col)`. При встрече новой высоты записывайте её. При повторной — сравнивайте: если новая ячейка лучше по столбцу, или равна по столбцу и лучше по строке, обновляйте. На запросы отвечайте за
Hint 2">↵
For each height, remember the cell with the smallest column index, and on ties — the smallest row index.↵
</spoiler>↵
↵
<spoiler summary="Solution">↵
Walk through the matrix and try to maintain `map<int, pair<int,int>>` where the key is the height and the value is the coordinates `(row, col)`. When you see a new height, record it. When you see it again — compare: if the new cell is better by column, or equal by column and better by row, update. Queries are answered in
 `O(log n)` черезvia `map`.↵
</spoiler>↵
↵
<spoiler summary="
КодCode">↵
```cpp↵
#include <bits/stdc++.h>↵
using namespace std;↵
↵
int main() {↵
    ios::sync_with_stdio(false);↵
    cin.tie(nullptr);↵
    int n, m, q;↵
    cin >> n >> m >> q;↵
    map<int, pair<int,int>> bestCell;↵
    for (int i = 1; i <= n; i++) {↵
        for (int j = 1; j <= m; j++) {↵
            int h;↵
            cin >> h;↵
            auto it = bestCell.find(h);↵
            if (it == bestCell.end()) {↵
                bestCell[h] = {i, j};↵
            } else {↵
                auto [row, col] = it->second;↵
                if (j < col || (j == col && i < row)) {↵
                    it->second = {i, j};↵
                }↵
            }↵
        }↵
    }↵
    while (q--) {↵
        int h;↵
        cin >> h;↵
        auto it = bestCell.find(h);↵
        if (it == bestCell.end()) {↵
            cout << -1 << '\n';↵
        } else {↵
            cout << it->second.first << ' '↵
                 << it->second.second << '\n';↵
        }↵
    }↵
    return 0;↵
}↵
```↵
</spoiler>↵
↵
---↵
↵
### F. 
Разрушение мостаBridge Destruction↵
↵
**Idea:** [user:Arbuzik342,2026-10-04]↵
**Preparation:** [user:Arbuzik342,2026-10-04], [user:zeyd1234,2026-10-04]↵
↵
<spoiler summary="
Подсказка 1">↵
Поддерживайте переменную `leftBorder` — минимальный номер уже разрушенной секции. Берляндия работает на
Hint 1">↵
Maintain a variable `leftBorder` — the smallest index among destroyed sections. Berlandia works on
 `[1, leftBorder-1]`, Флатландия — наFlatlandia works on `[leftBorder+1, n]`.↵
</spoiler>↵
↵
<spoiler summary="
Подсказка 2">↵
При равенстве прочностей Берляндия выбирает самую правую секцию, Флатландия — самую левую. Храните в дереве отрезков пару `(значение, индекс)`.↵
</spoiler>↵
↵
<spoiler summary="Решение">↵
Попробуйте завести два дерева отрезков: `treeBerland` для Берляндии с правилом «при равенстве — правый индекс», `treeFlatland` для Флатландии — «при равенстве — левый». Оба стройте по массиву `strength`. Секцию `m` сразу помечайте `INF`. Переменная `leftBorder = m`. На каждый ход: если `B`, запрашивайте минимум на
Hint 2">↵
On ties in strength, Berlandia picks the rightmost section, Flatlandia picks the leftmost. Store a pair `(value, index)` in the segment tree.↵
</spoiler>↵
↵
<spoiler summary="Solution">↵
Try to maintain two segment trees: `treeBerland` for Berlandia with the rule "on ties — rightmost index", and `treeFlatland` for Flatlandia with "on ties — leftmost index". Build both from the array `strength`. Mark section `m` as `INF` right away. Keep `leftBorder = m`. On each move: if `B`, query the minimum on
 `[1, leftBorder-1]` вin `treeBerland`; еслиif `F`, запрашивайте минимум наquery the minimum on `[leftBorder+1, n]` вin `treeFlatland`. Полученный индекс выводите, помечайте `INF` в обоих деревьях, обновляйтеPrint the returned index, mark it as `INF` in both trees, and update `leftBorder = min(leftBorder, idx)`. СложностьComplexity — `O((n + q) log n)`.↵
</spoiler>↵
↵
<spoiler summary="
КодCode">↵
```cpp↵
#include <bits/stdc++.h>↵
using namespace std;↵
↵
const int INF = 2e9 + 7;↵
↵
struct SegTree {↵
    int n;↵
    vector<pair<int,int>> tree;↵
    bool preferRight;↵
    SegTree(int sz, bool pr) : n(sz), preferRight(pr) {↵
        tree.resize(4 * sz + 4);↵
    }↵
    pair<int,int> combine(pair<int,int> a, pair<int,int> b) {↵
        if (a.first < b.first) return a;↵
        if (b.first < a.first) return b;↵
        if (preferRight) {↵
            return {a.first, max(a.second, b.second)};↵
        }↵
        return {a.first, min(a.second, b.second)};↵
    }↵
    void build(int v, int l, int r, const vector<int>& strength) {↵
        if (l == r) {↵
            tree[v] = {strength[l], l};↵
            return;↵
        }↵
        int mid = (l + r) / 2;↵
        build(2*v, l, mid, strength);↵
        build(2*v+1, mid+1, r, strength);↵
        tree[v] = combine(tree[2*v], tree[2*v+1]);↵
    }↵
    void update(int v, int l, int r, int pos) {↵
        if (l == r) {↵
            tree[v] = {INF, l};↵
            return;↵
        }↵
        int mid = (l + r) / 2;↵
        if (pos <= mid) {↵
            update(2*v, l, mid, pos);↵
        } else {↵
            update(2*v+1, mid+1, r, pos);↵
        }↵
        tree[v] = combine(tree[2*v], tree[2*v+1]);↵
    }↵
    pair<int,int> query(int v, int l, int r, int ql, int qr) {↵
        if (ql > r || qr < l) return {INF, -1};↵
        if (ql <= l && r <= qr) return tree[v];↵
        int mid = (l + r) / 2;↵
        pair<int,int> leftPart = query(2*v, l, mid, ql, qr);↵
        pair<int,int> rightPart = query(2*v+1, mid+1, r, ql, qr);↵
        return combine(leftPart, rightPart);↵
    }↵
};↵
↵
int main() {↵
    ios::sync_with_stdio(false);↵
    cin.tie(nullptr);↵
    int n, m;↵
    cin >> n >> m;↵
    vector<int> strength(n + 1);↵
    for (int i = 1; i <= n; i++) {↵
        cin >> strength[i];↵
    }↵
    string order;↵
    cin >> order;↵
    SegTree treeBerland(n, true), treeFlatland(n, false);↵
    treeBerland.build(1, 1, n, strength);↵
    treeFlatland.build(1, 1, n, strength);↵
    treeBerland.update(1, 1, n, m);↵
    treeFlatland.update(1, 1, n, m);↵
    int leftBorder = m;↵
    for (char c : order) {↵
        int idx;↵
        if (c == 'B') {↵
            idx = treeBerland.query(1, 1, n, 1, leftBorder - 1).second;↵
        } else {↵
            idx = treeFlatland.query(1, 1, n, leftBorder + 1, n).second;↵
        }↵
        cout << idx << ' ';↵
        treeBerland.update(1, 1, n, idx);↵
        treeFlatland.update(1, 1, n, idx);↵
        leftBorder = min(leftBorder, idx);↵
    }↵
    cout << '\n';↵
    return 0;↵
}↵
```↵
</spoiler>↵
↵
---↵
↵
### G. 
Просто не простоSimple but Not Simple↵
↵
**Idea:** [user:Arbuzik342,2026-10-04]↵
**Preparation:** [user:Arbuzik342,2026-10-04], [user:zeyd1234,2026-10-04]↵
↵
<spoiler summary="
Подсказка 1">↵
Все пары взаимно просты тогда и только тогда, когда ни одно простое число не делит одновременно два видимых числа
Hint 1">↵
All pairs are coprime if and only if no prime number divides two visible numbers at the same time
.↵
</spoiler>↵
↵
<spoiler summary="
Подсказка 2">↵
Попробуйте завести `divCount[p]` — сколько активных чисел делятся на `p`, и переменную `conflicts` — сколько простых имеют `divCount[p] ≥ 2`. Ответ растёт, когда `conflicts == 0`.↵
</spoiler>↵
↵
<spoiler summary="Решение">↵
Линейным решетом считайте наименьший простой делитель `spf[]` для всех чисел до `10^7`. Для запроса `x` получайте список его простых делителей. При `+x` увеличивайте `divCount[p]` для каждого делителя. Если `divCount[p]` стало равно `2`, увеличивайте
Hint 2">↵
Try to maintain `divCount[p]` — how many active numbers are divisible by `p`, and a variable `conflicts` — how many primes have `divCount[p] ≥ 2`. The answer grows when `conflicts == 0`.↵
</spoiler>↵
↵
<spoiler summary="Solution">↵
Compute the smallest prime factor `spf[]` for all numbers up to `10^7` using a linear sieve. For a query `x`, obtain the list of its prime divisors. On `+x`, increment `divCount[p]` for each divisor. If `divCount[p]` becomes `2`, increment
 `conflicts`. ПриOn `-x` уменьшайте, decrement `divCount[p]`. ЕслиIf `divCount[p]` стало равно `1`, уменьшайте `conflicts`. После обработки каждой команды, если `conflicts == 0`, добавляйте `1` к ответу. Сложностьbecomes `1`, decrement `conflicts`. After processing each command, if `conflicts == 0`, add `1` to the answer. Complexity — `O(MAX + q · log MAX)`, гдеwhere `MAX = 10^7`.↵
</spoiler>↵
↵
<spoiler summary="
КодCode">↵
```cpp↵
#include <bits/stdc++.h>↵
using namespace std;↵
↵
const int MAXV = 10000000;↵
↵
int main() {↵
    ios::sync_with_stdio(false);↵
    cin.tie(nullptr);↵
    vector<int> spf(MAXV + 1, 0);↵
    vector<int> primes;↵
    for (int i = 2; i <= MAXV; i++) {↵
        if (spf[i] == 0) {↵
            spf[i] = i;↵
            primes.push_back(i);↵
        }↵
        for (int p : primes) {↵
            if (p > spf[i] || (long long)i * p > MAXV) {↵
                break;↵
            }↵
            spf[i * p] = p;↵
        }↵
    }↵
    int q;↵
    cin >> q;↵
    vector<int> divCount(MAXV + 1, 0);↵
    int conflicts = 0, goodMoments = 0;↵
    while (q--) {↵
        string op;↵
        cin >> op;↵
        char sign = op[0];↵
        int value = stoi(op.substr(1));↵
        vector<int> primeFactors;↵
        while (value > 1) {↵
            int p = spf[value];↵
            primeFactors.push_back(p);↵
            while (value % p == 0) {↵
                value /= p;↵
            }↵
        }↵
        if (sign == '+') {↵
            for (int p : primeFactors) {↵
                divCount[p]++;↵
                if (divCount[p] == 2) {↵
                    conflicts++;↵
                }↵
            }↵
        } else {↵
            for (int p : primeFactors) {↵
                divCount[p]--;↵
                if (divCount[p] == 1) {↵
                    conflicts--;↵
                }↵
            }↵
        }↵
        if (conflicts == 0) {↵
            goodMoments++;↵
        }↵
    }↵
    cout << goodMoments << '\n';↵
    return 0;↵
}↵
```↵
</spoiler>↵
↵

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en1 English Arbuzik342 2026-10-04 22:30:47 16187 Initial revision for English translation
ru1 Russian Arbuzik342 2026-10-04 22:23:37 16168 Первая редакция (опубликовано)