Все мы хотим писать код быстрее и проще, особенно на соревнованиях, когда от времени отправки решения зависит место в таблице. Я собрал небольшой шаблон для соревнований по спортивному программированию.
Что тут есть?
Ввод/вывод
Несколько строк которые обычно всегда ускоряют ввод/вывод (cout.tie(0) ничего не делает):
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
С помощью этих строк, можно выводить и считывать вектора и пары, с помощью стандартных операторов:
template<typename T>istream& operator >>(istream& in, vector<T>& a) { range(i, a.size()) in >> a[i]; return in; }
template<typename T>ostream& operator <<(ostream& out, const vector<T>& a) { range(i, a.size()) out << a[i] << ' '; return out; }
template<typename T1, typename T2>istream& operator >>(istream& in, pair<T1, T2>& p) { in >> p.first >> p.second; return in; }
template<typename T1, typename T2>ostream& operator <<(ostream& out, const pair<T1, T2>& p) { out << p.first << ' ' << p.second; return out; }
Теперь можно просто делать вот так (Напомню вместо int можно использовать что угодно):
vector<int> a(n);
cin >> a;
cout << a;
pair<int,int> p;
cin >> p;
cout << p;
Дефайны
Один из самых полезных дефайнов:
#define all(x) x.begin(),x.end()
Теперь можно использовать:
sort(all(x))
Вместо
sort(x.begin(),x.end())
Дефайн специально для раундов КФ, умеет запускать несколько тестов:
#define CF(x) int x;cin >> x;while(x--)
Теперь можно делать так:
CF(___) {
//код
}
Немного упрощений для циклов:
#define range(i,n) for (int i=0;i<n;++i)
#define range(i, s, f) for (int i=(s);i<int(f);++i)
#define rrange(i,n) for (int i=n-1;i>=0;--i)
Этот дефайн ускорит ваш код, если вы часто используете модули. mod — глобальная переменная.
#define md(x) if (x>=mod) x%=mod
Не вижу шаблона для поиска гамильтонова пути в графе за $$$O(n)$$$, поэтому дизлайк.
Ещё очень хочется линейное дерево Гомори-Ху, но его тоже нет( Прошу автора как можно скорее исправить этот недостаток.
Постараюсь не говорить об объёме и полноте шаблона, как по мне, каждый просто записывает в шаблон то, что ему пригождается, и у каждого шаблон появляется самостоятельно. Тем не менее, раз этот стал выложено в общий доступ, то я чутка покритикую (прошу прощения за объём, мне просто стало интересно, сколько я смогу наскрести, тут есть и довольно бесполезные придирки, но большинство пунктов я считаю существенными):
Между
#include
и угловыми скобками хочется всегда либо пробел, либо его отсутствие. Видимо, по какому-то стандарту форматирования лучше пробел.Кажется, раз уж шаблон, то лучше подключить либо все-все полезные инклюды, либо
<bits/stdc++.h>
, если он у вас есть. Я подключаю его, и уж не помню, что есть полезного, но, видимо, как минимум<cmath>
забыт.Просто упомяну, что
cout.tie(0);
ничего не делает, подтверждение, но, разумеется, его можно писать, это не будет хуже, а может вам даже будет спокойнее, что вы не выкинули полезную строчку вместо бесполезной.В
#define
, если уж вы их пишете, аргумент надо заключать в круглые скобки — вот так:#define range(i, n) for (int (i) = 0; (i) < (n); ++(i))
, потому что#define
— это команда препроцессору произвести замену в вашем коде, препроцессор практически ничего не знает про синтаксис. Я не могу придумать адекватный пример, почемуall
может от этого сломаться, ноrange
безусловно их требует (и вообще, хорошая практикане писать дефайныв любом дефайне оборачивать аргумент в скобки), потому что если кто-то напишетrange(i, x ^ y)
, то внезапно, после подстановки получитсяfor (int i = 0; i < x ^ y; ++i)
, что эквивалентноfor (int i = 0; (i < x) ^ y; ++i)
, а вы, наверно, хотели не этого. Конечно, у^
вообще приоритет неудачный, но в записиrange(...)
вы с меньшей вероятностью найдёте ошибку, чем в записиfor (...)
— в последней фрагментi < x ^ y
хотя бы перед глазами.Ещё о дефайнах: раз уж у вас цикл обязательно на
int
ах, то озаботьтесь написать не простоn
, а(int)n
. Иначе вас постигнет неприятное, когда вы напишетеrrange(i, a.size()
для пустогоa
.a.size()
имеет беззнаковый (unsigned) типsize_t
, при вычитании 1 (типаint
) оба аргумента приведутся к типуsize_t
, результат тоже будет беззнаковый, поэтому получится ни больше ни меньше, как $$$2^{64}-1$$$, цикл в итоге будет бесконечным, так какint i
всегда меньше этого заоблачного значения.Довольно желательно добавить
const
перед типом переменной в операторе вывода, чтобы показать компилятору, что эта функция не меняет пару или вектор. Если вы пишете что-то такоеvoid function(const vector<int> &v)
, то это вообще необходимо, вдруг вы захотите вывестиv
изнутри функции — просто не подойдёт тип, текущий оператор вывода принимает только неконстантные объекты. Ну, а если не пишете, то, наверно, ничего не сломается, но вообще писатьconst
неизменяющимся переменным — хорошая практика контроля себя.Довольно желательно, чтобы вывода использовал не
cout
, аout
, переданный в качестве аргумента. Если вы всё время при выводе пишетеcout << ...
, то это эквивалентно, но к вашему удивлению, записьcerr << v
также выведетv
в стандартный поток вывода, вstdout
, а отнюдь не вstderr
. Ну, и, разумеется, это будет вести себя неожиданно, если вы используетеifstream
при работе с файлами, и пытаетесь вызвать оператор вывода уifstream
. Всё это касается иcin
.В C++20 завезли
<ranges>
, и теперь макрос#define all(x) (x).begin(),(x).end()
не нужен, поскольку можно просто написатьstd::ranges::sort(x)
(вместоstd::sort(all(x))
).Да, и из-за отсутствия скобок макросы
range
иrrange
забагованы:cout.tie(0)
)))))))))))
Автокомментарий: текст был обновлен пользователем antonkasko (предыдущая версия, новая версия, сравнить).
Автокомментарий: текст был обновлен пользователем antonkasko (предыдущая версия, новая версия, сравнить).