Team «МегаПачкаЧипсовЛейс» is the first to solve task G after 8 minutes 🎈
Team «Yet another team from Moscow» is the first to solve task D after 35 minutes 🎈
Team «Yet another team from Moscow» is the first to solve task B2 after 37 minutes 🎈
🔥3
Team «Ось Астана-Семей» is the first to solve task A after 76 minutes 🎈
😱17
Congratulations to team «Yet another team from Moscow» for being the first to solve all 12 tasks before the end of the contest! 🎈
🤯18🎉7
Deadline to send screen records is 15th of June, send it to the d.tatar@acc.bc-pf.org mail. Write your team name and team members’ names
Almaty Code Cup pinned «Deadline to send screen records is 15th of June, send it to the d.tatar@acc.bc-pf.org mail. Write your team name and team members’ names»
EDITORIAL
Task A
Task A involves identifying matching pairs of brackets in a sequence. We'll build a tree (or a forest) of nested bracket pairs (which can be done by traversing the string with a stack once). Note that removing a pair of brackets doesn't affect who is paired with whom. Removing a pair of brackets in the tree means removing a vertex and reattaching its children to the parent of the removed vertex. The answer to the task is the number of trees in the forest, which is the same as the number of roots in the forest. For convenience, we'll replace s with "(" + s + ")" so that we have exactly one tree with a non-removable root, and the answer will be the number of its children. We'll implement dynamic programming dp[v][k] representing the maximum number of roots we can obtain in the subtree of vertex v by removing exactly k vertices. This can be easily recalculated as dp[v][k] = max(dp[x][k1] + dp[y][k - k1]). Note that this dynamic programming works in O(n^2) because each pair of vertices in the tree contributes a constant amount of actions in recalculating this DP when we process their LCA.
Task B1:
For obtaining the maximum value, it is not advantageous to include a bit with a '-' sign, and it is advantageous to include a bit with a '+' sign. Conversely, for obtaining the minimum value, the opposite is true.
Task B2:
We'll convert the input data into standard bit strings and store them in a trie from higher bits to lower bits. To find the maximum value max(x ^ y) for a number x, we need to traverse the trie and check: if the current bit sign is '+', whether we can include the bit in the number (x ^ y); if it's '-', whether we can exclude this bit. Note: instead of using a trie, we can simply use lower_bound on an array.
Task C:
We'll show that with the optimal strategy, Pladis will either win within no more than two of his turns, or he will definitely lose. For Pladis to win, he needs to make one of the brackets equal to zero. If initially there is a bracket with identical symbols (like (a|a) or (!b|!b)), he can nullify it on his first move. Suppose there are no such brackets. If there is a symbol that occurs with the same sign with two different other variables (like {(a|b)&(a|d)} or {(!a|x)&(!a|!x)}), Pladis will also win by nullifying this symbol in both brackets and then nullifying one of the remaining symbols on his second move (or Znry will do this for Pladis in the second example). Otherwise, all symbols split into pairs, and Znry will simply complete each bracket for Pladis up to one. This means that it's enough to check the existence of Pladis' first move for which, regardless of Znry's move, he can win with his second move.
Task D
For each segment, we'll project it onto the Ox axis by finding formulas for the images of the points through the similarity of triangles. After that, we can either perform a scanline to include and exclude segments or sort the obtained projections, merge them into non-overlapping segments, and count the answer. It's important to read the input data as integers because floating-point numbers read slowly (TL53).
Task E
We'll precompute all the queries and solve the task offline. For each value of z, we'll remember which queries had this value x == z and which elements of the array a[i] == z. We'll create a segment tree for the XOR operation and initialize it with zeros. We'll iterate through the values of z from 1 to 10^6. For each z, we'll iterate through all i such that a[i] == z and update the segment tree tree.update(pos = i, val = a[i]). After this, we'll answer all queries with x == z simply by querying tree.get(l, r) because all elements a[j] > x are currently zeroed in it, and the answer will be calculated correctly.
Task A
Task A involves identifying matching pairs of brackets in a sequence. We'll build a tree (or a forest) of nested bracket pairs (which can be done by traversing the string with a stack once). Note that removing a pair of brackets doesn't affect who is paired with whom. Removing a pair of brackets in the tree means removing a vertex and reattaching its children to the parent of the removed vertex. The answer to the task is the number of trees in the forest, which is the same as the number of roots in the forest. For convenience, we'll replace s with "(" + s + ")" so that we have exactly one tree with a non-removable root, and the answer will be the number of its children. We'll implement dynamic programming dp[v][k] representing the maximum number of roots we can obtain in the subtree of vertex v by removing exactly k vertices. This can be easily recalculated as dp[v][k] = max(dp[x][k1] + dp[y][k - k1]). Note that this dynamic programming works in O(n^2) because each pair of vertices in the tree contributes a constant amount of actions in recalculating this DP when we process their LCA.
Task B1:
For obtaining the maximum value, it is not advantageous to include a bit with a '-' sign, and it is advantageous to include a bit with a '+' sign. Conversely, for obtaining the minimum value, the opposite is true.
Task B2:
We'll convert the input data into standard bit strings and store them in a trie from higher bits to lower bits. To find the maximum value max(x ^ y) for a number x, we need to traverse the trie and check: if the current bit sign is '+', whether we can include the bit in the number (x ^ y); if it's '-', whether we can exclude this bit. Note: instead of using a trie, we can simply use lower_bound on an array.
Task C:
We'll show that with the optimal strategy, Pladis will either win within no more than two of his turns, or he will definitely lose. For Pladis to win, he needs to make one of the brackets equal to zero. If initially there is a bracket with identical symbols (like (a|a) or (!b|!b)), he can nullify it on his first move. Suppose there are no such brackets. If there is a symbol that occurs with the same sign with two different other variables (like {(a|b)&(a|d)} or {(!a|x)&(!a|!x)}), Pladis will also win by nullifying this symbol in both brackets and then nullifying one of the remaining symbols on his second move (or Znry will do this for Pladis in the second example). Otherwise, all symbols split into pairs, and Znry will simply complete each bracket for Pladis up to one. This means that it's enough to check the existence of Pladis' first move for which, regardless of Znry's move, he can win with his second move.
Task D
For each segment, we'll project it onto the Ox axis by finding formulas for the images of the points through the similarity of triangles. After that, we can either perform a scanline to include and exclude segments or sort the obtained projections, merge them into non-overlapping segments, and count the answer. It's important to read the input data as integers because floating-point numbers read slowly (TL53).
Task E
We'll precompute all the queries and solve the task offline. For each value of z, we'll remember which queries had this value x == z and which elements of the array a[i] == z. We'll create a segment tree for the XOR operation and initialize it with zeros. We'll iterate through the values of z from 1 to 10^6. For each z, we'll iterate through all i such that a[i] == z and update the segment tree tree.update(pos = i, val = a[i]). After this, we'll answer all queries with x == z simply by querying tree.get(l, r) because all elements a[j] > x are currently zeroed in it, and the answer will be calculated correctly.
❤4
Task F
Since arrays a[] and b[] are symmetrical, let's assume that a[] has fewer inversions than b[]. Note that if b[] has at least one inversion, then there will be a pair of neighboring elements b[i] = 1 and b[i + 1] = 0. Swapping them will decrease the number of inversions by one, while swapping any pair of neighboring elements can change the number of inversions by no more than one. Hence, the answer is the absolute difference in the number of inversions in b[] and a[].
Task G
Write the string in a circle and for each pair of adjacent characters, calculate the number of steps required to move from one to the other on the keyboard (Manhattan distance). The answer will be the sum of all such distances minus the distance from s[l] to s[1]. A cyclic shift of the string allows you to move this subtracted transition anywhere, so it's optimal to move it to the position with the maximum distance to the next character.
Task H
If the second attack deals more damage than the first, always use it when possible; otherwise, always use the first attack.
Task I
Since you can stop at vertices, it makes sense to calculate dp[v] for each vertex v — the smallest time at which we can arrive at it. Looking closely, this dp suits Dijkstra's algorithm, and we just need to apply it.
Task J
If x = 1, then p >= 2 and all fractions are simply zero. Let's assume x >= 2. Note that floor(x / y) = (x - (x mod y)) / y. Consequently, floor(1 / p) + floor(x / p) + ... + floor(x^n / p) = (1 - (1 mod p)) / p + (x - (x mod p)) / p + ... + (x^n - (x^n mod p)) / p = ((1 + x + ... + x^n) - (1 mod p) - (x mod p) - ... - (x^n mod p)) / p. The sum 1 + x + ... + x^n can be found using the geometric series formula (x^{n + 1} - 1) / (x - 1). Note that x^k mod p is cyclic with a period of p - 1 by Fermat's Little Theorem, so it's enough to calculate the contribution of the remainder x^k mod p for each 0 <= k <= p - 1 and find the answer.
Task K
Plot points on a line and represent the constraint p[i] <= x as a half-interval [p[i], inf), and p[i] >= x as a half-interval (-inf, p[i]]. We need to find the point that lies in the minimum number of half-intervals. Hence, we can consider all queries offline and compress the coordinates to [1, n + m]. For each p[i], update the segment tree with += 1 for all points that do not fall within the corresponding interval (essentially saying that they need to change the sign of one additional inequality). For p[i] <= x, for example, perform tree.update(l = 1, r = p[i] - 1, val += 1). Then process the queries incrementally, updating the segment tree and querying tree.getmin(1, n + m).
Since arrays a[] and b[] are symmetrical, let's assume that a[] has fewer inversions than b[]. Note that if b[] has at least one inversion, then there will be a pair of neighboring elements b[i] = 1 and b[i + 1] = 0. Swapping them will decrease the number of inversions by one, while swapping any pair of neighboring elements can change the number of inversions by no more than one. Hence, the answer is the absolute difference in the number of inversions in b[] and a[].
Task G
Write the string in a circle and for each pair of adjacent characters, calculate the number of steps required to move from one to the other on the keyboard (Manhattan distance). The answer will be the sum of all such distances minus the distance from s[l] to s[1]. A cyclic shift of the string allows you to move this subtracted transition anywhere, so it's optimal to move it to the position with the maximum distance to the next character.
Task H
If the second attack deals more damage than the first, always use it when possible; otherwise, always use the first attack.
Task I
Since you can stop at vertices, it makes sense to calculate dp[v] for each vertex v — the smallest time at which we can arrive at it. Looking closely, this dp suits Dijkstra's algorithm, and we just need to apply it.
Task J
If x = 1, then p >= 2 and all fractions are simply zero. Let's assume x >= 2. Note that floor(x / y) = (x - (x mod y)) / y. Consequently, floor(1 / p) + floor(x / p) + ... + floor(x^n / p) = (1 - (1 mod p)) / p + (x - (x mod p)) / p + ... + (x^n - (x^n mod p)) / p = ((1 + x + ... + x^n) - (1 mod p) - (x mod p) - ... - (x^n mod p)) / p. The sum 1 + x + ... + x^n can be found using the geometric series formula (x^{n + 1} - 1) / (x - 1). Note that x^k mod p is cyclic with a period of p - 1 by Fermat's Little Theorem, so it's enough to calculate the contribution of the remainder x^k mod p for each 0 <= k <= p - 1 and find the answer.
Task K
Plot points on a line and represent the constraint p[i] <= x as a half-interval [p[i], inf), and p[i] >= x as a half-interval (-inf, p[i]]. We need to find the point that lies in the minimum number of half-intervals. Hence, we can consider all queries offline and compress the coordinates to [1, n + m]. For each p[i], update the segment tree with += 1 for all points that do not fall within the corresponding interval (essentially saying that they need to change the sign of one additional inequality). For p[i] <= x, for example, perform tree.update(l = 1, r = p[i] - 1, val += 1). Then process the queries incrementally, updating the segment tree and querying tree.getmin(1, n + m).
Задача A: Особенные пары --- буквально соответствующие пары скобок в последовательности. Построим дерево (лес) вложенности этих пар скобок (достаточно один раз пройти стеком по строке). Заметим, что удаление какой-то пары скобок никак не влияет на то кто с кем остается в паре. Заметим, что удаление пары скобок на дереве значит удаление какой-то вершины и переподвешивание её детей к предку удалаяемой вершины. Ответом на задачу является количество деревьев в лесу, что то же самое, что количество корней в лесу. Для удобства заменим s = "(" + s + ")" чтобы у нас было ровно одно дерево и неудаляемый корень, при этом ответом будет количество его детей. Сделаем ДП вида dp[v][k] --- максимальное количество корней которое мы можем получить в поддереве вершины v удалив ровно k вершин. Это можно легко пересчитывать как dp[v][k] = max(dp[x][k1] + dp[y][k - k1]). Остается заметить что это ДП работает за O(n^2), потому что каждая пара вершин в дереве внесет константу действий в пересчет этой дпшки ровно когда мы будем обрабатывать их LCA.
Задача B1: Для получения максимального значения нам не выгодно включать бит у которого знак '-' и выгодно включать бит где знак '+'. Для получения минимального значения наоборот.
Задача B2: Переведем входные данные в обычные битовые строки и сохраним их в боре от больших битов к меньшим. Чтобы для числа x найти максимальное значение max(x ^ y) надо спускаться по бору и проверять: если текущий знак бита это '+', то можно ли включить бит в числе (x ^ y), если же это '-', то можно ли этот бит наоборот выключить. P.S. вместо бора можно просто делать lower_bound'ы на массиве.
Задача C: Покажем, что при оптимальной стратегии либо Пладислав выиграет за не более чем два своих хода, либо он точно проиграет. Для того чтобы Пладу победить он должен какую-то из скобок сделать равной нулю. Если изначально есть скобка с одинаковыми символами ((a|a) или (!b|!b) например), то он может первым же ходом её занулить. Допустим что таких скобок нет. Если есть символ, который встречается с одинаковым знаком с двумя разными другими переменными ({(a|b)&(a|d)} или {(!a|x)&(!a|!x)} например), то Плад также победит занулив сначала этот символ в обоих скобках и вторым своим ходом занулит один из оставшихся символов (либо Жнри это сделает за Плада как во втором примере). В противном случае все символы разбиваются на пары и Жнри просто будет доделывать каждую скобку за Пладом до единицы. Это значит, что достаточно проверить существование первого хода Плада для которого при любом ходе Жнри он сможет его победить своим вторым ходом.
Задача D: Для каждого отрезка спроецируем его на прямую Ox найдя формулы для образов точек через подобие треугольников. После этого можно либо сделать scanline включая и выключая отрезки, либо отсортировать полученные проекции, объеденить в непересекающиеся и посчитать ответ. Важно считывать входные данные в целочисленные типы данных, потому что числа с плавающей точкой медленно считываются (ТЛ53).
Задача E: Считаем все запросы заранее и решим задачу оффлайн. Для каждого значения z запомним у каких запросов было это значение x == z и какие элементы массива a[i] == z. Создадим дерево отрезков на операцию ксора и проинициализируем его нулями. Пойдем по значениям z от 1 до 10^6. Для очередного z пройдем по всем i таким что a[i] == z и обновим в ДО tree.update(pos = i, val = a[i]). После этого ответим на все запросы с x == z просто запросом tree.get(l, r), потому что все элементы a[j] > x в нем сейчас занулены и ответ посчитается корректно.
Задача F: Так как массивы a[] и b[] равноправны, то предположим, что в a[] инверсий меньше чем в b[]. Заметим, что если в b[] есть хотя бы одна инверсия, то в нем найдется пара соседних элементов b[i] = 1 и b[i + 1] = 0. Если поменять их местами, то количество инверсий уменьшится на один, при этом переставление любой пары соседних элементов может изменить количество инверсий не более чем на один. Отсюда ответ это модуль разности количества инверсий в b[] и a[].
Задача B1: Для получения максимального значения нам не выгодно включать бит у которого знак '-' и выгодно включать бит где знак '+'. Для получения минимального значения наоборот.
Задача B2: Переведем входные данные в обычные битовые строки и сохраним их в боре от больших битов к меньшим. Чтобы для числа x найти максимальное значение max(x ^ y) надо спускаться по бору и проверять: если текущий знак бита это '+', то можно ли включить бит в числе (x ^ y), если же это '-', то можно ли этот бит наоборот выключить. P.S. вместо бора можно просто делать lower_bound'ы на массиве.
Задача C: Покажем, что при оптимальной стратегии либо Пладислав выиграет за не более чем два своих хода, либо он точно проиграет. Для того чтобы Пладу победить он должен какую-то из скобок сделать равной нулю. Если изначально есть скобка с одинаковыми символами ((a|a) или (!b|!b) например), то он может первым же ходом её занулить. Допустим что таких скобок нет. Если есть символ, который встречается с одинаковым знаком с двумя разными другими переменными ({(a|b)&(a|d)} или {(!a|x)&(!a|!x)} например), то Плад также победит занулив сначала этот символ в обоих скобках и вторым своим ходом занулит один из оставшихся символов (либо Жнри это сделает за Плада как во втором примере). В противном случае все символы разбиваются на пары и Жнри просто будет доделывать каждую скобку за Пладом до единицы. Это значит, что достаточно проверить существование первого хода Плада для которого при любом ходе Жнри он сможет его победить своим вторым ходом.
Задача D: Для каждого отрезка спроецируем его на прямую Ox найдя формулы для образов точек через подобие треугольников. После этого можно либо сделать scanline включая и выключая отрезки, либо отсортировать полученные проекции, объеденить в непересекающиеся и посчитать ответ. Важно считывать входные данные в целочисленные типы данных, потому что числа с плавающей точкой медленно считываются (ТЛ53).
Задача E: Считаем все запросы заранее и решим задачу оффлайн. Для каждого значения z запомним у каких запросов было это значение x == z и какие элементы массива a[i] == z. Создадим дерево отрезков на операцию ксора и проинициализируем его нулями. Пойдем по значениям z от 1 до 10^6. Для очередного z пройдем по всем i таким что a[i] == z и обновим в ДО tree.update(pos = i, val = a[i]). После этого ответим на все запросы с x == z просто запросом tree.get(l, r), потому что все элементы a[j] > x в нем сейчас занулены и ответ посчитается корректно.
Задача F: Так как массивы a[] и b[] равноправны, то предположим, что в a[] инверсий меньше чем в b[]. Заметим, что если в b[] есть хотя бы одна инверсия, то в нем найдется пара соседних элементов b[i] = 1 и b[i + 1] = 0. Если поменять их местами, то количество инверсий уменьшится на один, при этом переставление любой пары соседних элементов может изменить количество инверсий не более чем на один. Отсюда ответ это модуль разности количества инверсий в b[] и a[].
❤2🥰1
Задача G: Выпишем строку по кругу и для каждой пары соседних символов посчитаем количество шагов чтобы перейти из одного в другой по клавиатуре (манхеттенское расстояние). Ответом будет сумма всех таких расстояний минус расстояние из s[l] в s[1]. Циклический сдвиг строки позволяет переместить этот отнимаемый переход куда угодно, поэтому оптимально переместить его в позицию с максимальным расстоянием до следующего символа.
Задача H: Если вторая атака наносит больше урона, чем первая, то делаем её всегда когда можем, иначе всегда делаем первую атаку.
Задача I: Так как в вершинах можно останавливаться, то логично для каждой вершины посчитать dp[v] --- самый маленький момент времени когда мы сможем в неё приехать. Если аккуратно посмотреть, то такое dp подходит для алгоритма Дейкстры и нужно просто его применить.
Задача J: Если x = 1, то p >= 2 и все дроби просто равны нулю. Пусть x >= 2. Заметим, что floor(x / y) = (x - (x mod y)) / y. Следовательно floor(1 / p) + floor(x / p) + ... + floor(x^n / p) = (1 - (1 mod p)) / p + (x - (x mod p)) / p + ... + (x^n - (x^n mod p)) / p = ((1 + x + ... + x^n) - (1 mod p) - (x mod p) - ... - (x^n mod p)) / p. Сумму 1 + x + ... + x^n можно найти по формуле сокращенного умножения (x^{n + 1} - 1) / (x - 1). Заметим, что x^k mod p по малой теореме Ферма циклично с периодом p - 1, следовательно достаточно для каждого 0 <= k <= p - 1 посчитать вклад остатка x^k mod p в общую сумму и найти ответ.
Задача K: Нарисуем точки на прямой и ограничение p[i] <= x сделаем в виде полуинтервала [p[i], inf), а p[i] >= x в виде полуинтервала (-inf, p[i]]. Тогда нам надо найти точку, которая не лежит на минимальном количестве полуинтервалов. Отсюда понятно, что можно считать все запросы в оффлайн и сжать координаты до [1, n + m]. Теперь для каждого p[i] в дереве отрезков сделаем += 1 на все точки, которые не входят в соответствующий интервал (то есть буквально скажем, что им надо изменить знак одного дополнительного неравенства); для p[i] <= x нужно сделать tree.update(l = 1, r = p[i] - 1, val += 1) например. Теперь пройдем по запросам постепенно обновляя дерево отрезков и делая запрос tree.getmin(1, n + m).
Задача H: Если вторая атака наносит больше урона, чем первая, то делаем её всегда когда можем, иначе всегда делаем первую атаку.
Задача I: Так как в вершинах можно останавливаться, то логично для каждой вершины посчитать dp[v] --- самый маленький момент времени когда мы сможем в неё приехать. Если аккуратно посмотреть, то такое dp подходит для алгоритма Дейкстры и нужно просто его применить.
Задача J: Если x = 1, то p >= 2 и все дроби просто равны нулю. Пусть x >= 2. Заметим, что floor(x / y) = (x - (x mod y)) / y. Следовательно floor(1 / p) + floor(x / p) + ... + floor(x^n / p) = (1 - (1 mod p)) / p + (x - (x mod p)) / p + ... + (x^n - (x^n mod p)) / p = ((1 + x + ... + x^n) - (1 mod p) - (x mod p) - ... - (x^n mod p)) / p. Сумму 1 + x + ... + x^n можно найти по формуле сокращенного умножения (x^{n + 1} - 1) / (x - 1). Заметим, что x^k mod p по малой теореме Ферма циклично с периодом p - 1, следовательно достаточно для каждого 0 <= k <= p - 1 посчитать вклад остатка x^k mod p в общую сумму и найти ответ.
Задача K: Нарисуем точки на прямой и ограничение p[i] <= x сделаем в виде полуинтервала [p[i], inf), а p[i] >= x в виде полуинтервала (-inf, p[i]]. Тогда нам надо найти точку, которая не лежит на минимальном количестве полуинтервалов. Отсюда понятно, что можно считать все запросы в оффлайн и сжать координаты до [1, n + m]. Теперь для каждого p[i] в дереве отрезков сделаем += 1 на все точки, которые не входят в соответствующий интервал (то есть буквально скажем, что им надо изменить знак одного дополнительного неравенства); для p[i] <= x нужно сделать tree.update(l = 1, r = p[i] - 1, val += 1) например. Теперь пройдем по запросам постепенно обновляя дерево отрезков и делая запрос tree.getmin(1, n + m).
🤯3🥰1
RUS:
Уважаемые финалисты!
Всем командам-финалистам были высланы приглашения на финал на почту капитана, которую он указывал при регистрации. Пожалуйста, подтвердите свое участие. Обращаем ваше внимание, что все участники команды должны быть школьниками.
Командам, занявшим места после 40-го, приглашения могут приходить позже в случае отказа участия некоторых команд.
KAZ:
Құрметті финалисттер!
Барлық финалист командаларға финалға шақырулар капитанның тіркеу кезінде көрсеткен поштасына жіберілді. Қатысуды растауларыңызды сұраймыз. Команда мүшелерінің барлығы мектеп оқушылары болуы керектігін ескертеміз.
40-шы орыннан кейінгі командаларға кейбір командалардың қатысудан бас тартуы жағдайында шақырулар кейінірек келуі мүмкін.
ENG:
Dear Finalists,
Invitations have been sent to all finalist teams for the final to the captain's email provided during registration. Please confirm your participation. Please note that all team members must be school students.
Teams placed after the 40th position may receive invitations later in case some teams decline to participate.
Уважаемые финалисты!
Всем командам-финалистам были высланы приглашения на финал на почту капитана, которую он указывал при регистрации. Пожалуйста, подтвердите свое участие. Обращаем ваше внимание, что все участники команды должны быть школьниками.
Командам, занявшим места после 40-го, приглашения могут приходить позже в случае отказа участия некоторых команд.
KAZ:
Құрметті финалисттер!
Барлық финалист командаларға финалға шақырулар капитанның тіркеу кезінде көрсеткен поштасына жіберілді. Қатысуды растауларыңызды сұраймыз. Команда мүшелерінің барлығы мектеп оқушылары болуы керектігін ескертеміз.
40-шы орыннан кейінгі командаларға кейбір командалардың қатысудан бас тартуы жағдайында шақырулар кейінірек келуі мүмкін.
ENG:
Dear Finalists,
Invitations have been sent to all finalist teams for the final to the captain's email provided during registration. Please confirm your participation. Please note that all team members must be school students.
Teams placed after the 40th position may receive invitations later in case some teams decline to participate.
👍4❤1🤯1😱1
Forwarded from ОФ Beyond Curriculum
Хотите помогать школьникам открывать мир науки? Сделайте пожертвование на организацию APhB, WSO, ACC, NChB
Ваше пожертвование поддержит проведение Алматинских физических боев, турнира по ракетостроению WSO, Национальных химических боев и Олимпиады по программированию ACC.
Beyond Curriculum объединяет более 100 энтузиастов из ведущих школ и университетов (MIT, Yale, Brown, UPenn, NYUAD, Georgia Tech, KAIST, HKUST, МФТИ, NU) и призеров международных олимпиад.
Мы из первых рук знаем, насколько важны соревнования: они создают сообщество увлеченных учеников, выявляют таланты и мотивируют детей развиваться в науке.
Как сделать пожертвование: перейдите на сайт bc-pf.org/crowdfund, выберите соревнование (APhB, NChB, ACC, WSO), укажите сумму пожертвования, введите ваш E-mail и примите условия договора. Остатки средств после турниров будут переведены в общий Фонд Развития. Все пожертвования будут учтены и отражены в отчетах. Поддержите будущее науки!
Ваше пожертвование поддержит проведение Алматинских физических боев, турнира по ракетостроению WSO, Национальных химических боев и Олимпиады по программированию ACC.
Beyond Curriculum объединяет более 100 энтузиастов из ведущих школ и университетов (MIT, Yale, Brown, UPenn, NYUAD, Georgia Tech, KAIST, HKUST, МФТИ, NU) и призеров международных олимпиад.
Мы из первых рук знаем, насколько важны соревнования: они создают сообщество увлеченных учеников, выявляют таланты и мотивируют детей развиваться в науке.
Как сделать пожертвование: перейдите на сайт bc-pf.org/crowdfund, выберите соревнование (APhB, NChB, ACC, WSO), укажите сумму пожертвования, введите ваш E-mail и примите условия договора. Остатки средств после турниров будут переведены в общий Фонд Развития. Все пожертвования будут учтены и отражены в отчетах. Поддержите будущее науки!
❤2