Недавно я, решая очередную задачу на codeforces, я столкнулся с необходимостью написания элементарной функции нахождения НОД, и тогда я задумался: "Неужели нет встроенной функции для его нахождения? Это же базовый алгоритм.". Забредя в дебри интернета, я решил поглубже изучить возможности C++ 14 для лучшего написания олимпиад. Итак, я организую рубрику полезных функций языка с точки зрения олимпиадного программирования.

'

С помощью ',можно обочначать границы числа, не меняя его значения

int x = 1'020'011; // int x = 1020011

Также в переменные можно записывать числа в двоичной системе счисления

int x = 0b0110 // int x = 6

Битовые операции

В C++ есть встроенные битовые операции над числами, которые позволяют быстрее осуществлять некоторые привычные операции.

Основные из них:

  • k & n - побитовое И

  • k | n - побитовое ИЛИ

  • k ^ n - побитовый XOR

  • k << n - сдвинуть все биты числа k на n битов влево

  • k >> n - сдвинуть все биты числа k на n битов вправо

Благодаря данным операциям мы можем ускорить наш код:

А давайте быстро умножим/поделим n на степень двойки

n = n << 1; // Умножить n на 2
n = n >> 1; // Разделить n на 2

Проверим ка чётность числа

В двоичной записи числа четность или нечетность числа определяет последний бит (т.к. только нулевая степень двойки нечетна), тогда если у данного числа в двоичной записи последний бит положителен, то оно нечетна, иначе четно. Такой трюк не сильно лучше получения остатка от деления (%), но работает быстрее с большими числами.

if(n & 1){
  cout << "Нечетное" << endl;
}
else{
  cout << "Четное" << endl;
}

Перестановка двух чисел местами

Нам даже не потребуется третья переменная

a ^= b;
b ^= a;
a ^= b;

Проверка на степень двойки

int isPowerOfTwo(int x){
 	return (x & (!(x&(x-1)))); 
}

Если число является степенью двойки, тогда его двоичная запись имеет лишь один активный бит, отнимая один, мы активируем все биты до степени двойки и тогда x & (x-1) = 0, иначе есть активные биты перед самым значимым, а значит он останется активным после x-1 и x & (x-1) > 0

Лямбды

Эта тема стоит отдельного поста (в будущем сделаю), а сейчас расскажу в общих чертах.

Лямбда-выражение - определяет анонимную функцию внутри другой функции. Такие выражения позволяют определить функцию максимально близко к месту её вызова и не захламлять пространство имен лишними несложными выражениями.

Они имеют следующий синтаксис:

[captureClause] (параметры) -> возвращаемый тип {тело лямбды};

Есть два способа объявления лямбды:

auto sum = [](auto a,auto b){return a+b;};
cout << sum(1,2); // 3
find_if(all(arr),
              	[](string str) {
                	return (str.find("nut") != string::npos);
                  });

Данные выражения удобно использовать для обозначения незначимых функций внутри одной, чтобы не громоздить кучу лишних имен функций и кода.

Полезные STL контейнеры

Обычно я пробегался циклом для проверки правильности массива, но, оказывается, есть более простая альтернатива такому методу.

// Проверим все ли элементы правильные
all_of(v.begin,v.end(),isRight());
// Проверим есть ли хотя бы один правильный элемент
any_of(v.begin,v.end(),isRight());
// Проверим все ли элементы НЕ правильные
none_of(v.begin,v.end(),isRight());
// Получим позицию правильного элемента или его отсутствие
find_if(v.begin,v.end(),isRight());
// Если результат = v.end(), значит в данном массиве нет такого элемента

Итог

Это то, что я нашел интересным за последние два дня и решил запечатлеть эти подсказки в виде небольшой статьи. Надеюсь она также будет кому-то полезна.