Skip to content

Instantly share code, notes, and snippets.

@reverofevil
Last active November 7, 2022 11:32
Show Gist options
  • Save reverofevil/ba01c0bc543dec7cac9473b0ca21024f to your computer and use it in GitHub Desktop.
Save reverofevil/ba01c0bc543dec7cac9473b0ca21024f to your computer and use it in GitHub Desktop.
C++ minimum for competitive programming

By sharpc and udpn. Code samples by Evil_Stivie.

This is theoretical STL minimum for competitive programmers, a subset of features of C++ standard library useful for solving algorithmic problems. Topics are grouped mostly by STL header file name and context of use. Almost all names you might encounter in this guide are in std namespace. For it, and only for it, you should add below all #includes:

using namespace std;

<iostream>, <iomanip>

cout, cin, while (cin >> ...)

Input/output streams are preferred to C functions, because they need no format string, and are free from common mistakes made in it.

int n = 123123123;
char ch = 'a' + 3;
long long ll = 92233720368547758LL;
cout << n << " " << ch << " " << ll << endl; // 123123123 d 92233720368547758

Similarly, input requires neither format strings nor pointers.

int k;
cin >> k;
cout << k << endl;

Some problems have no exact input size, and the input is terminated with EOF (run.exe<file or Ctrl-Z in stdin). Overloaded operator >> for streams returs istream& that can be implicitly converted to bool. The resulting value is !fail(), and fail() fail returns true trying to read after EOF.

int k, sum = 0;
while (cin >> k) { // reads until EOF
    sum += k;
}
cout << sum << endl; // sum of numbers on input until EOF

getline, while+getline, getline after cin

Some problems ask to input string until newline character is encountered. Naïve string s; cin >> s; inputs string to first space-like character. This is done with getline, that returns istream& too with same same handling of EOF. Terminating newline character is not added to string variable.

aa bb
cc ddddd^Z
string s1, s2;
while (getline(cin, s1)) { // reads until EOF
    s2 += s1;
}
cout << s2.length() << endl; // 13

It should be added, that cin >> var; doesn't consume newline character from input stream, thus it might be needed to do one more getline call to consume it explicitly.

stringstream ss("5\na b c");
int n;
string s;
ss >> n;
getline(ss, s); // consumes newline after 5
getline(ss, s); // reads second line
cout << n << " : " << s << endl; // 5 : a b c

<iomanip>: fixed, setprecision, setw, setfill, hex/dec

The header <iomanip> contains formatting related features, which mostly replace format strings of printf.

Manipulators setprecision and fixed set precision for all subsequent << calls for floating-point numbers, by setting number of all digits or digits after the point correspondingly.

double n = 3.141592653;
cout << setprecision(5) << n << endl; // 3.1416
cout << fixed << setprecision(5) << n << endl; // 3.14159

A pair setw and setfill set how to pad subsequent number or string, and which character to use for that padding.

cout << setw(8) << "hello" << endl; // "   hello"
cout << setfill('0') << setw(3) << 7 << endl; // "007"

Manilpulators hex and dec output subsequent numbers in hexadecimal and decimal numeral systems.

int n;
stringstream("2A") >> hex >> n;
cout << dec << n << endl; // 42
cout << hex << 42 << endl; // 2a

<iomanip>: noskipws/skipws

By defautlt cin inputs several chars, skipping all space-like characters. Manipulators noskipws/skipws switch this behavior.

char s1, s2, s3;
stringstream("a b c") >> s1 >> s2 >> s3;
cout << s1 << ", " << s2 << ", " << s3 << endl; // a, b, c
stringstream("a b c") >> noskipws >> s1 >> s2 >> s3;
cout << s1 << "," << s2 << "," << s3 << endl; // a, ,b

cin/cout.tie(0); cin/cout.sync_with_stdio(false); endl vs '\n'

Input/output streams were developed in a way to extensively expand and modify their state. Ensuing overhead can make solutions hit time limits on online judges. In such cases there are magic words of

cin.tie(0);
cin.sync_with_stdio(false);

for ample inputs, and another one, with cout, for ample outputs.

Usually, in competitive programming it's expected to use << endl to put newline character to the output. It's equivalent to << '\n' << flush. Manipulator flush flushes output buffer, and in case of large number of rows this makes code ridiculously slow. In such case, all endl should be replaced by "\n", with only one endl or flush left at the end of the program.

<cstdio>: printf/scanf for ample inputs

If this is not enough yet to squeeze iostreams into time limit (if it's really the case, and only one), it's fine to use functions from C.

int n;
long long n_l;
double d;
float f;
char s[5];
char ch;
scanf("%d %lld %lf %f %s %c", &n, &n_l, &d, &f, &s, &ch);
printf("%d %lld %lf %f %s %c", n, n_l, d, f, s, ch);

<vector>

Instead of arrays C++ programs should always use sequence container vector. Its size is set as constructor argument. It's possible to set different default value (other than 0, "", false and empty vector) for items with second constructor argument.

vector<int> v(5); // {0,0,0,0,0}
vector<vector<int>> v(2, vector<int>(3, -1)); // {{-1,-1,-1}, {-1,-1,-1}}

For size and default value:

vector<double> v;
v.assign(4, 1.0); // {1.0, 1.0, 1.0, 1.0}

Vector can be initialized with initialization lists or a pair of iterators.

vector<int> v{1, 2, 3, 4, 5};
vector<int> v2(v.begin() + 2, v.begin() + 4); // {3, 4}

Access to item is same as for an array.

cout << v2[0]; // 3

Vectors have almost same performance as arrays, thus in release build they don't check for array boundaries. There is a way to access an item with explicit array boundary check, and throw an exception in case of boundary violation:

cout << v2.at(2); // Exception: out_of_range

clean != empty

Clean (don't confuse with emptyness check, v.empty() (are there people, that do?)), works for any container.

v.clear();

begin, end, rbegin, rend

There are several ways to iterate over container (examples are for vector):

vector<int> v{1, 2, 3}

// By index
for (int i = 0; i < v.size(); ++i) {
    cout << v[i] << endl;
}

// By iterator
// auto = vector<int>::iterator
for (auto it = v.begin(); it != v.end(); ++it) {
    cout << *it << endl;
}

// Recommended: C++11 range-based for
for (int item : v) {
    cout << item << endl;
}

Containers can be traversed in reverse order:

// auto = vector<int>::reverse_iterator
for (auto it = v.rbegin(); it != v.rend(); ++it) {
    cout << *it << endl;
}

push_back, pop_back, emplace_back, front, back

Vector is a dynamic array with an ability to append to the end new elements (push_back) and resize (size), both in amortized O(1) time. To achieve this complexity, vector allocates more memory than it's strictly required (the exact amount is available from capacity() method call result). When the memory limit is reached (.size() == .capacity()) it allocates 1.5-2 times more memory (the multiplier is for MSVC), and copies all items. Memory reallocation invalidates all previously created iterators for that vector, which might lead to errors.

vector<int> v;
for (int i = 0; i < 16; ++i) {
    v.push_back(123);
    cout << v.size() << "-" << v.capacity() << " ";
}
// 1-1 2-2 3-3 4-4 5-6 6-6 7-9 8-9 9-9 10-13 11-13 12-13 13-13 14-19 15-19 16-19

If an item to be appended has to be constructed first (for example, a pair), constructor and push_back could be merged into single call to avoid extraneous calls to copy constructor.

vector<pair<int, string>> v;
// Instead of v.push_back(make_pair(5, "hello"));
v.emplace_back(5, "hello");

In addition to appending to the end, it's possible to delete items from the end.

vector<int> v{1, 2, 3};
v.pop_back(); // {1, 2}

First and last item are accessible by reference returned by front() and back() method calls correspondingly.

vector<int> v{2, 4, 8, 16, 32};
cout << v.front() << endl; // 2
cout << v.back() << endl; // 32
v.back() = -1; // {2, 4, 8, 16, -1}

insert

It's possible to insert a value or a segment (defined by iterator pair) after a position given by an iterator. All elements subsequent to iterator before the insertion ({2, 3} and {6, 2, 3} in the example) are copied in O(N) time.

vector<int> v{1, 2, 3};
vector<int> w{5, 6};
v.insert(v.begin() + 1, w.begin(), w.end()); // {1, 5, 6, 2, 3}
v.insert(v.begin() + 2, 8); // {1, 5, 8, 6, 2, 3}

size, resize, capacity, reserve, swap hack/shrink_to_fit

Existing vector can be resized.

vector<int> v{1, 2, 3};
v.resize(5, -1); // {1, 2, 3, -1, -1}

Its capacity can also be changed to avoid time-consuming memory reallocations in case it's upper bound on item quantity is known in advance.

cout << v.size() << " " << v.capacity() << endl; // 5 5
v.reserve(1000);
cout << v.size() << " " << v.capacity() << endl; // 5 1000

While reserve can be used only to increase capacity, vector can be recreated with same item values and minimal capacity in one line (so called "swap hack"). It might be useful if momentary sizes of vectors are bigger than sizes when computations on them are finished, especially in case there are vector<vector<...>>s somewhere in the code.

v.swap(vector<int>(v));
cout << v.size() << " " << v.capacity() << endl; // 5 5

In C++ you can use .shrink_to_fit() to same effect.

vector<bool>

Vector is specialized for bool, so that each element takes only 1 bit of memory. It saves memory, but operations on such vector are slower, and it's impossible to get a pointer to item. If increased cost of operations is not desired, vector<int> (or vector of other integral numeric type) can be used. Boolean operators will cast numeric values to boolean, so barely any change in code is required.

<string>

Instead of zero-terminated C-strings C++ programs should always use string.

string s = "hello, world!";
char c = s[6]; // same as s.at(6) for vectors
cout << s << endl; 
s += c; s += s; // Concatenation: "hello, world! hello, world! "

string(10, ' '), std::string("a") + "b"

Constructor for string — just like vector's — takes number of characters and character to repeat.

cout << string(5, '!') << endl; // "!!!!!"

For C compatibility reasons string literal "a" is char const *, and + doesn't concanate them.

string s = "AaBb";
// s += "C" + "c"; // results in compile error
s += string("C") + "c"; // correct
cout << s << endl; // AaBbCc

C++14 now has another literal to construct strings.

string s = "a"s + "b";

length/size, substr

Same as vector, string has methods assign, clear, empty, begin, end, rbegin, rend, size, resize, capacity, reserve. Also there is an alias for size: length.

string t = "Hedgehog is gonna get out from that jail";
cout << t.size() << endl; // 40
cout << t.length() << endl; // 40

Substring (0-based first character, length):

string t = "abcdef";
cout << t.substr(2, 3) << endl; // cde

push_back

Same as vector, string has methods push_back, pop_back, front, back, insert.

string s;
for (int i = 0; i < 10; ++i) {
    s.push_back('a' + i);
}
cout << s << endl; // abcdefghij

to_string, stoi

Numeric types can be cast to string with to_string, and vice versa with stoi/stoll/stoull/stof/stod.

double pi = 3.14159265;
string s = "Pi = " + to_string(pi);
cout << s << endl; // Pi = 3.141593

s = "12345678901";
// cout << stoi(s) << endl; // Exception: out_of_range
cout << stoll(s) << endl; // 12345678901

find, rfind, find_*_of, string::npos

It's possible to find substrings in a string (using a naïve search algorithm with O(NM) complexity). Optional second argument is offset to the position to start search. If there is no such substring, return value is string::npos.

string s = "hello, world!";
//          0123456789012
cout << s.find("wo") << endl; // 7
cout << boolalpha << (s.find("hi") == string::npos) << endl; // true

Search from the end (the string to be found should be no more to the right than offset):

string s = "hello, world!";
//          0123456789012
cout << s.rfind("l", 9) << endl; // 3

This loop finds all occurences of substring.

size_t off = 0;
while (true) {
    off = s.find("l", off);
    if (off == string::npos) { break; }
    cout << off << endl; // 2 3 10
    off += 1;
}

Besides substrings, it's possible to find characters from a set of characters with find_first_of method. Similarly, find_first_not_of finds characters not in set, and find_last_of and find_last_not_of do the same from the end of the string.

string s = "hello, world!";
//          0123456789012
cout << s.find_last_of("aeiou") << endl; // last vower is at position 8

<sstream>: stringstream ss("str"), ss.str()

String stream works similarly to cin/cout, but instead of working with stdin/stdout it modifies an internal string.

stringstream ss;
ss << 2 << " " << 4 << " " << 8;
string s = ss.str(); // read internal string
cout << s << endl; // "2 4 8"

stringstream ss("1 2 3"); // initialize internal string
int n1, n2, n3;
ss >> n1 >> n2 >> n3;
cout << n1 << " " << n2 << " " << n3 << endl; // 1 2 3

<cctype>

isalpha, isalnum, isblank, isdigit, islower, isupper, isxdigit

These character classes are most useful in competitive programming. Lists of characters are only of those that are in 0-127 code range.

  • isalpha — A-Za-z
  • isalnum — 0-9A-Za-z
  • isblank — \t and space
  • isdigit — 0-9
  • islower — a-z
  • isupper — A-Z
  • isxdigit — 0-9A-Fa-f

tolower, toupper, usage with transform

Expectedly transform A-Z into a-z and vice versa. To transform whole string, transform from <algorithm> should be used.

string s = "where is STL?!";
transform(s.begin(), s.end(), s.begin(), toupper);
cout << s << endl; // WHERE IS STL?!

<deque>

Deque is similar to vector, but allows appends and removals from both ends in O(1) time. It's implemented by circular buffer of dynamic size with pointers to segments of items of equal length.

deque<int> d;
d.push_back(3);
d.push_front(2);
d.push_back(4);
d.push_front(1);
d.push_back(5);
for (int i = 0; i < d.size(); ++i) {
    cout << d[i] << " ";
}
cout << endl; // 1 2 3 4 5

There are also std::stack and std::queue built on top of deque. They are just wrappers on deque without some of the methods.

<queue>: priority_queue

Priority queue allows insertions in O(logN) time, search for biggest element in O(1), and its removal in O(logN). It's implemented as binary heap on vector that supports A[i] >= A[2*i + 1] && A[i] >= A[2*i + 2] invariant for all i.

priority_queue<int> pq;
for (int i = 0; i < 5; ++i) {
    pq.push(i);
}
while (pq.size()) {
    int item = pq.top();
    cout << item << " ";
    pq.pop();
}
cout << endl; // 4 3 2 1 0

Usually priority queue is used for pairs of (priority, task), where it got its name from

priority_queue<pair<int, char>> pq;
for (int i = 0; i < 5; ++i) {
    pq.emplace(i, 'a' + i);
}
cout << pq.top().second << endl; // e

<tuple>: pair, make_pair, .first/.second; tuple, make_tuple, get<#>();

Two or more associated values can be joined into a pair or a tuple. Elements of a pair are accessible through fields first and second.

pair<int, int> p(1, 2);
cout << p.first << " " << p.second << endl; // 1 2
p = make_pair(14, 28);
cout << p.first << " " << p.second << endl; // 14 28

Elements of tuple are accessible through a function template get:

tuple<int, int, int> tp(1, 2, 3);
cout << get<0>(tp) + get<1>(tp) + get<2>(tp) << endl; // 6
tp = make_tuple(14, 28, 42);
cout << get<0>(tp) + get<1>(tp) + get<2>(tp) << endl; // 84

Lexicographic comparison

For sequence containers (vector, string, deque, pair, tuple) STL defines operator <, that compares them lexicographically (first by first element, in case they are equal by second, etc), so they can be compared, and containers that stores them can be sorted.

Comparison of vectors:

vector<int> box1(3), box2(3);
for (int i = 0; i < 3; ++i) { cin >> box1[i]; }
for (int i = 0; i < 3; ++i) { cin >> box2[i]; }

sort(box1.begin(), box1.end());
sort(box2.begin(), box2.end());

if (box1 <= box2) {
    cout << "You can put the first box into the second one" << endl;
} else if (box2 <= box1) {
    cout << "You can put the second box into the first one" << endl;
} else {
    cout << "You can't put one box into another" << endl;
}

Comparison of strings:

cout << boolalpha << (string("a") < string("abcd")) << endl; // true
cout << boolalpha << (string("a") < string("ABCD")) << endl; // false

Comparison of pairs:

cout << boolalpha << (make_pair(1, 2) < make_pair(1, 3)) << endl; // true

<map>, <set>

map, sorted keys

STL has container map (associative array, dictionary) that associates to a key of any type with < operator defined a value of any type. It's implemented as an almost balanced binary red-black tree, so that accessing an element by key takes O(logN) comparisons, as well as insertion or removal of an element. Red-black tree is ordered by keys, and all keys are unique.

[key]= vs at, for (auto kv : mapa) { }

Call to [] operator automatically creates a value for given key with default constructor for value type if there was no value for that key previously. Thus for const map<..., ...> instead of [] operator an at() method should be used that throws an out_of_range exception if the key doesn't exist.

Iteration on map gives pair<TKey, TValue>.

map<char, int> m;
for (char ch : string("abacaba")) {
    m[ch] += 1;
}
cout << m.size() << endl; // 7
for (auto kv : m) {
    cout << kv.first << "-" << kv.second << " ";
} // a-4 b-2 c-1

Note that keys are iterated over in ascending order.

count, erase

A check that m.find(key) (returns iterator) is not equal to m.end() succeeds if a value for a given key is in a map. Another way to do the check is count method call.

map<char, int> m{{'a', 1}, {'c', 1}, {'b', 0}, {'d', 2}, {'f', 1}};
cout << m.count('a') << " " << m.count('e') << endl; // 1 0

Elements are removed by erase method, either by key, iterator or two-iterator segment.

m.erase('c'); // {'a': 1, 'b': 0, 'd': 2, 'f': 1}
m.erase(m.find('f')); // {'a': 1, 'b': 0, 'd': 2}

set, insert

Container set is similar to map, but stores no values, and, consequently, no []. Insertion of new values is done with insert that takes an element or a segment given by two iterators.

set<int> s{1, 2, 3, 5, 6};
cout << s.count(1) << " " << s.count(4) << endl; // 1 0

cout << s.size() << endl; // 5
s.insert(2);
cout << s.size() << endl; // 5
s.insert(0);
cout << s.size() << endl; // 6

vector<int> add{6, 7, 8};
s.insert(add.begin(), add.end());

s.erase(7);

for (int item : s) {
    cout << item << " "; // 0 1 2 3 5 6 8
}

<unordered_set>, <unordered_map>

STL implements open hash-table that allows inserting of keys in O(1) amortized time. Its implementation relies on std::list that stores all inserted elements in the order of container traversal, and pointers into this list to first and last element for each of b = 2n buckets in a vector of 2 * b length. Number of possibly stored items in buckets is kept no less than number of items. When hash-table capacity is exhausted, number of buckets is increased to be twice higher (8 times higher in MSVC for small hash-tables) and hashes for all elements are recomputed with std::hash.

Containers unordered_map and unordered_set are mostly similar to map and set, but keys are sorted by hash % u.bucket_count().

unordered_set<char> u;
for (int i = 0; i < 26; ++i) {
    u.insert('a' + i);
}
for (char ch : u) {
    cout << ch;
} // iabcdefghjklmnopqrstuvwxyz

std::hash<T>::operator()

Function hash is implemented for most data types as "exclusive or" with next byte and multiplication, iterated. But for some useful types like tuples, hash has to be implemented by user:

namespace std {
template<typename T1, typename T2> struct hash<pair<T1, T2>> {
    size_t operator () (pair<T1, T2> const& arg) const {
        return hash<T1>()(arg.first) ^ hash<T2>()(arg.second);
    }
};
}

<algorithm>

STL implements some simple and often used generic algorithms. "Generic" they are, because there pay no difference to the type of container, because they take just a pair of iterators.

min, max, minmax, max_element, min_element

Minimum, maximum, both of them:

cout << min(123, 456) << " " << min('a', 'b') << endl; // 123 a
cout << max(2.5, 2.6) << " " << max('k', 'o') << endl; // 2.6 o
pair<int, int> res = minmax({ 2, 4, 8, 16, 32 });
cout << res.first << ' ' << res.second << endl; // 2 32

Maximum of a sequence (min_element for minimum), returns an iterator:

vector<int> v{1, 2, 3, 4, 5};
cout << max_element(v.begin(), v.end()) - v.begin() << endl; // index 4
cout << *max_element(v.begin(), v.end()) << endl; // value 5

sort, predicate with tie, stable_sort, is_sorted

A sort:

vector<int> v{2342, 1231, 87978, 123, 789};
sort(v.begin(), v.end()); // 123 789 1231 2342 87978

A reverse sort:

sort(v.rbegin(), v.rend()); // 87978 2342 1231 789 123

A sort with comparison predicate:

vector<int> v{-2, -1, 0, 1, 2, 3};
sort(v.begin(), v.end(), [](int a, int b) {
    return abs(a) < abs(b);
}); // 0 -1 1 -2 2 3

A sort with lexicographical comparison predicate (tie creates a tuple of references); an example sorts characters first by frequency in descending order, then by character code in ascending order:

string s = "hello, world!";
map<char, int> m;
for (char ch : s) { m[ch] += 1; }
vector<pair<char, int>> v(m.begin(), m.end());
sort(v.begin(), v.end(), [](pair<char, int> const& a, pair<char, int> const& b) {
    return tie(-a.second, a.first) < tie(-b.second, b.first);
}); // {{'l', 3}, {'o', 2}, {' ', 1}, {'!', 1}, {',', 1}, {'d', 1}, {'e', 1}, {'h', 1}, {'r', 1}, {'w', 1}}

Stable sort doesn't change initial order for values that are equal, [comparison predicate]-wise.

vector<pair<char, int>> v(m.rbegin(), m.rend());
stable_sort(v.begin(), v.end(), [](pair<char, int> const& a, pair<char, int> const& b) {
    return -a.second < -b.second;
}); // {{'l', 3}, {'o', 2}, {'w', 1}, {'r', 1}, {'h', 1}, {'e', 1}, {'d', 1}, {',', 1}, {'!', 1}, {' ', 1}}

Check that the sequence is already sorted:

vector<int> v{1, 2, 3, 1};
cout << boolalpha << is_sorted(v.begin(), v.end()) << endl; // false
sort(v.begin(), v.end());
cout << boolalpha << is_sorted(v.begin(), v.end()) << endl; // true

sort/iota + next_permutation

Function next_permutation iterates over permutations (returning false if current permutation is lexicographically the biggest). In competitive programming usually permutations of indices get iterated over. In this case source sequence is usually created with iota. If not, almost all the time it's a lexicographically smallest permutation of values, that is easily computed by sort.

vector<int> v(4);
iota(v.begin(), v.end(), 1);
do {
    cout << v[0] << v[1] << v[2] << v[3] << "; ";
} while (next_permutation(v.begin(), v.end()));
// 1234; 1243; 1324; 1342; 1423; 1432; 2134; 2143; 2314; 2341; 2413; 2431; 3124; 3142; 3214; 3241; 3412; 3421; 4123; 4132; 4213; 4231; 4312; 4321;

unique/remove/remove_if + .erase

Generic algorithms can move elements, but cannot remove them. The container itself is responsible for that. Function unique searches for multiple (second and so on) sequent (next to each other) occurences of items, and moves them to the end of container. In order for unique to return a sequence of only unique items, sequence has to be sorted first. Functions remove/remove_if move a certain value or values that pass a check by predicate to the end of container. They return iterator to first moved item, that can be used to remove all the items between it and the end of container with erase.

vector<int> v = {1, 1, 2, 3, 3, 3, 1, 1, 2, 2};
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end()); // 1 2 3
v.erase(remove_if(v.begin(), v.end(), [](int x) {
    return x % 2 == 0;
}), v.end()); // 1 3

reverse

Reverse the order of items in sequence container:

string s = "desserts";
reverse(s.begin(), s.end());
cout << s << endl; // stressed

fill, copy, copy_n, <iterator>: back_inserter, istream_iterator

A whole range of functions are intended to fill containers with items from some source. Every time you use memset, a kitten dies. Functions back_inserter and inserter create an insertion iterator, that calls push_back or insert correspondingly on a container passed to their constructors as argument when it's dereferenced and assigned a value.

vector<int> a(5); // {0, 0, 0, 0, 0}
fill(a.begin() + 1, a.end(), -1); // {0, -1, -1, -1, -1}
copy(a.begin(), a.begin() + 2, a.begin() + 2); // {0, -1, 0, -1, -1}
vector<int> b;
copy_n(a.rbegin(), 3, back_inserter(b)); // {-1, -1, 0}

STL has an iterator class (that only supports reading and writing to it) for input and output streams. Default constructor of istream_iterator allows to read until EOF.

stringstream ss("5\n1 2 3 4 5\n1 1 2 3 5");
int n;
ss >> n;
vector<int> v, w;
copy_n(istream_iterator<int>(ss), n, back_inserter(v)); // v = {1, 2, 3, 4, 5}
copy(istream_iterator<int>(ss), istream_iterator<int>(), back_inserter(w)); // w = {1, 1, 2, 3, 5}
copy(w.begin(), w.end(), ostream_iterator<int>(cout, ", ")); cout << endl; // 1, 1, 2, 3, 5, 

most vexing parse

On a rare occasion a peculiar ambiguity is met (so called "most vexing parse") when a programmer thinks, that w is a definition of variable with 2 arguments passed into constructors, but compiler thinks it's a function declaration.

vector<int> w(istream_iterator<int>(ss), istream_iterator<int>());

MSVC will warn something in the lines of

warning C4930: prototyped function not called (was a variable definition intended?)

Just add a pair of (seemingly extraneous) brackets around one of the arguments to convince compiler that it's really a variable definition.

stringstream ss("1 2 3 4 5");
vector<int> w((istream_iterator<int>(ss)), istream_iterator<int>());
copy(w.begin(), w.end(), ostream_iterator<int>(cout, "_")); // 1_2_3_4_5_

find, find_if, count, count_if

Functions find/find_if find iterator to first value equal to the given or satisfying a given predicate. Functions count/count_if count, how many of such values there are in total.

vector<int> v{0, 1, 1, 2, 3, 5, 8, 13, 21, 34};
cout << find(v.begin(), v.end(), 8) - v.begin() << endl; // 6
cout << *find_if(v.begin(), v.end(), [](int i) { return i > 10; }) << endl; // 13
cout << count(v.begin(), v.end(), 1) << endl; // 2
cout << count_if(v.begin(), v.end(), [](int i) { return i % 2 == 0; }) << endl; // 4

search

Function search searches for sequences of values (unlike string::find that searches for only one), similar to a search of substring in a string.

vector<int> v{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6};
auto seq = {3, 5};
cout << search(v.begin(), v.end(), seq.begin(), seq.end()) - v.begin() << endl; // 9

includes, set_union, set_intersection, set_difference, set_symmetric_difference

Set-theoretic operations are done on sorted segments (usually on vectors due to smaller overhead).

Inclusion:

vector<int> v1{2, 8, 16, 32};
vector<int> v2{2, 4, 8};
vector<int> v3{8, 16};
cout << boolalpha << includes(v1.begin(), v1.end(), v2.begin(), v2.end()); // false
cout << boolalpha << includes(v1.begin(), v1.end(), v3.begin(), v3.end()); // true

Union, intersection, difference and symmetric difference (require one iterator to mark the place to store their result):

vector<int> v1{10, 20, 30, 40};
vector<int> v2{40, 50, 60, 70};
vector<int> res0111, res0001, res0100, res0110;

set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(res0111));
// 10 20 30 40 50 60 70
set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(res0001));
// 40
set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(res0100));
// 10 20 30
set_symmetric_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(res0110));
// 10 20 30 50 60 70

lower_bound/upper_bound

Integer binary search finds in ascending-sorted segment (for vectors — in O(logN) time) a segment [begin, end[, containing this value.

vector<int> v{1, 1, 1, 1, 2, 2, 2, 3, 3, 4};
cout << "2 in [" <<
    lower_bound(v.begin(), v.end(), 2) - v.begin() << "; " <<
    upper_bound(v.begin(), v.end(), 2) - v.begin() << "[" << endl; // 2 in [4; 7[

If it's desirable to compute "items" on the fly by "index", custom iterator class can be used.

struct int_iterator : iterator<random_access_iterator_tag, int> {
    int n;
    function<int(int)> pred;
    int_iterator(int n, function<int(int)> pred) : n(n), pred(pred) { }
    int operator * () const { return pred(n); }
    operator int () const { return n; }
    int_iterator& operator ++ () { return *this += 1; }
    int_iterator& operator += (int rhs) { n += rhs; return *this; }
};
function<int(int)> pred = [](int x) {
    if (x < 100500) { return -1; }
    if (x > 100600) { return 1; }
    return 0;
};
int_iterator it_begin(0, pred), it_end(1000000, pred);
cout << "[" <<
    lower_bound(it_begin, it_end, 0) << ", " <<
    upper_bound(it_begin, it_end, 0) << "[" << endl; // [100500, 100601[

<iterator>: begin(cont), end(cont), size(cont)

Instead of .begin()/.end()/.size() methods on containers, global begin(cont)/end(cont)/size(cont) functions can be used, that also support arrays and strings from C.

cout << size("abcde") << endl; // 6, because there's also \0 character in the end

<numeric>: accumulate, partial_sum, iota

Sum of all values on a segment of container, defined by a pair of iterators. Type of resulting value is the same as type of initial value (sum vector<int64_t> to 0LL).

vector<int> v{1, 2, 3, 4};
cout << accumulate(v.begin(), v.end(), 0) << endl; // 10

Partial sums:

vector<int> v{1, 2, 3, 4, 5}, res(5);
partial_sum(v.begin(), v.end(), res.begin()); // 1 3 6 10 15

Generation of a sequence of values (with a prefix increment operator ++):

vector<int> v(5);
iota(v.begin(), v.end(), -2); // -2 -1 0 1 2

<cmath>

There's a lot of math functions. Only popular and non-obvious given here.

hypot, atan2, pi = atan(1) * 4

L2-distance (hypotenuse of right triangle). More precise, but slower than naïve computation:

cout << hypot(4, 3) << endl; // 5

Function atan2(y, x) computes the angle (in ]−π, +π]) between x axis and the ray to (x, y). It's an arctangent of y / x that takes into consideration operand signs, and also handles 0 / 0 case:

cout << atan2(10, -10) << " radians" << endl; // 2.35619

π is not in standard yet. To avoid compiler-specific macros or manual definition, it's possible to use atan(1) = π / 4:

double const pi = atan(1) * 4; // 3.1415926535897931
cout << setprecision(20) << pi << " " // 3.141592653589793116
    << nexttoward(pi, 3.0) << " "  // 3.1415926535897926719
    << nextafter(pi, 4.0) << endl; // 3.1415926535897935601

round, floor, ceil

Rounding down to next integer:

cout << floor(2.7) << " " << floor(-2.5) << endl; // 2 -3

Rounding up:

cout << ceil(2.7) << " " << ceil(-2.5) << endl; // 3 -2

Rounding to closest integer (half-integers rounding outwards from 0):

cout << round(2.7) << " " << round(-2.5) << endl; // 3 -3

abs

Absolute value:

cout << abs(-10) << endl; // 10

<complex>

Complex numbers can be used to shorten some 2D geometry calculations. For example, generation of coordinate offsets on square grid to 4-neighbors

complex<int> dir(1, 0);
for (int i = 0; i < 4; ++i) {
    cout << dir << " " << dir.real() << " + " << dir.imag() << "j" << endl;
    // (1,0) 1 + 0j; (0, 1) 0 + 1j; (-1, 0) -1 + 0j; (0, -1) 0 + -1j
    dir *= complex<int>(0, 1);
}

or triangle area.

stringstream ss("1 1\n1 4\n5 1");
double x, y;
ss >> x >> y; complex<double> a(x, y);
ss >> x >> y; complex<double> b(x, y);
ss >> x >> y; complex<double> c(x, y);
complex<double> A = b - a, B = c - a;
double S = abs((conj(A) * B).imag()) / 2.0;
cout << S << endl; // 6

Don't forget that in times of war a value for sine can be as high as four.

cout << sin(1.570796327 - 2.063437069i) << endl; // (4,7.94362e-10)

<limits>: numeric_limits<int>::max()

For all "unachievably big" and sentinel values (like 1e9) precise maximum and minimum values can be used.

cout << numeric_limits<int64_t>::min() << endl; // -9223372036854775808
cout << numeric_limits<int64_t>::max() << endl; //  9223372036854775807

<random>

Pseudo-random number generators are rarely used in competitive programming in a fair way, but sometimes randomized solution is hard to challenge. By default C++ uses mt19937 generator.

default_random_engine generator;
generator.seed(0);
uniform_real_distribution<double> distribution(0.0, 1.0); // similarly, uniform_int_distribution<int>
double rnd = distribution(generator);
cout << rnd << endl; // 0.592845

<utility>: swap

Swap values:

int x = 5, y = 3;
swap(x, y);
cout << x << " " << y << endl; // 3 5

<bitset>

Bit representation with known number of digits might be easy to show with bitset.

cout << bitset<10>(777) << endl; // 1100001001

<chrono>: std::chrono::high_resolution_clock::now()

Precise time measurement:

auto t0 = chrono::high_resolution_clock::now();
this_thread::sleep_for(1.0s);
auto t1 = chrono::high_resolution_clock::now();
cout << chrono::duration_cast<chrono::milliseconds>(t1 - t0).count() << endl; // 999
cout << chrono::duration<double>(t1 - t0).count() << endl; // 0.999376

<functional>

With the addition of lambda-functions in C++11 it became much easier to write callback functions. function template class is very useful to store them in variables (mostly for recursive lambda-functions, otherwise auto works just fine) or take them as arguments.

stringstream ss("6 5\n0 1\n0 2\n1 3\n1 4\n4 5");
int n, m;
ss >> n >> m;
vector<vector<int>> adjlist(n);
for (int i = 0; i < m; ++i) {
    int a, b;
    ss >> a >> b;
    adjlist[a].push_back(b);
    adjlist[b].push_back(a);
}

int time = 0;
function<void(int, int, function<void(int, int)>)> dfs =
    [&adjlist, &time, &dfs](int v, int from, function<void(int, int)> enter) {
        enter(v, time++);
        for (int nn : adjlist[v]) {
            if (nn != from) {
                dfs(nn, v, enter);
            }
        }
        time++;
    };

dfs(0, -1, [](int v, int time) {
    cout << "Entered " << v << " at time " << time << endl;
});
/*
Entered 0 at time 0
Entered 1 at time 1
Entered 3 at time 2
Entered 4 at time 4
Entered 5 at time 5
Entered 2 at time 9
*/

Compiler-specific: __builtin_popcount, __builtin_clz, __builtin_ctz, __gcd, __int128

These intrinsic functions might be useful. They compute in one assembler instruction number of set bits in a number (popcount), number of zeros in binary representation until first 1 is met, counting from the left (clz — count leading zeroes) and from the right (ctz — count trailing zeroes). Intrinsic functions are compiler-specific. These are only for MSVC or GCC.

#if defined(_MSC_VER)
#include <intrin.h>
#define popcount __popcnt
#define popcount64 __popcnt64
#elif defined(__GNUC__)
#define popcount __builtin_popcount
#define popcount64 __builtin_popcountll
#endif

#if defined(_MSC_VER)
#include <intrin.h>
int clz(uint32_t x) { unsigned long result = -1; _BitScanReverse(&result, x); return 31 - result; }
int ctz(uint32_t x) { unsigned long result = -1; _BitScanForward(&result, x); return result; }
int clz64(uint64_t x) { unsigned long result = -1; _BitScanReverse64(&result, x); return 63 - result; }
int ctz64(uint64_t x) { unsigned long result = -1; _BitScanForward64(&result, x); return result; }
#elif defined(__GNUC__)
#define clz __builtin_clz
#define ctz __builtin_ctz
#define clz64 __builtin_clzll
#define ctz64 __builtin_ctzll
#endif

uint64_t num = 0x000000F000000000ULL;
cout << "popcount: " << popcount64(num) << endl; // 4
cout << "leading 0s: " <<  clz64(num) << " trailing: " << ctz64(num) << endl; // 24 36

uint32_t num2 = 0x000F0000;
cout << "popcount: " << popcount(num2) << endl; // 4
cout << "leading 0s: " << clz(num2) << " trailing: " << ctz(num2) << endl; // 12 16

In C++17 std::gcd was added to <numeric> header, but previously there was none. In GCC it was part of implementation of std::rotate, and could be accessed as __gcd. In MSVC it's available in boost library.

#if defined(_MSC_VER)
#include <boost/math/common_factor.hpp>
using boost::math::gcd;
#elif defined(__GNUC__)
#define gcd __gcd
#endif

cout << gcd(2983479376572795LL, 29837483726583645LL) << endl; // 15

64-bit GCC extends a set of predefined integral numeric types with __int128. In MSVC it has to be taken from boost too.

#if defined(_MSC_VER)
#include <boost/multiprecision/cpp_int.hpp>
typedef boost::multiprecision::int128_t int128_t;
#elif defined(__GNUC__)
typedef __int128 int128_t;
#endif

int128_t result = int128_t(2983479376572795LL) * 29837483726583645LL;
cout << int(result % 1000000007) << endl; // 493398412

Это теоретический минимум по STL для занимающихся спортивным программированием, подмножество возможностей стандартной библиотеки C++, полезных для решения алгоритмических задач. Группировка преимущественно по заголовку и контексту использования. Почти все упоминаемые имена лежат в пространстве имен std, для него и только для него следует использовать после #include

using namespace std;

Объяснения к каждому пункту под катом. Соавтор — udpn. Большинство примеров кода любезно предоставлены Evil_Stivie.

Еще вас могут заинтересовать:

Лексика решений TopCoder

Гримуар C++

<iostream>, <iomanip>

cout, cin, while (cin >> ...)

Потоки ввода-вывода предпочтительнее, чем сишные функции, поскольку не нуждаются в форматной строке и свободны от ошибок в ней.

int n = 123123123;
char ch = 'a' + 3;
long long ll = 92233720368547758LL;
cout << n << " " << ch << " " << ll << endl; // 123123123 d 92233720368547758

Аналогично, ввод не требует форматной строки и использования указателей.

int k;
cin >> k;
cout << k << endl;

В некоторых задачах точный размер ввода не дан и вводить предлагается до EOF (run.exe<file или Ctrl-Z в stdin). Перегрузка оператора >> у потоков ввода возвращает istream&, который может быть неявно скастован к bool, каст возвращает !fail(), а fail() возвращает true при попытке чтения после EOF.

int k, sum = 0;
while (cin >> k) { // читает до EOF
    sum += k;
}
cout << sum << endl; // сумма введенных до EOF целых чисел

getline, while+getline, getline после cin

В некоторых задачах требуется выполнить ввод всей строки до перевода строки, простое string s; cin >> s; вводит до первого пробельного символа. Тогда следует использовать getline, который тоже возвращает istream& с тем же способом обработки EOF. Завершающий перевод строки не пишется в строковую переменную.

aa bb
cc ddddd^Z
string s1, s2;
while (getline(cin, s1)) { // читает до EOF
    s2 += s1;
}
cout << s2.length() << endl; // 13

Следует добавить, что cin >> var; не вводит перевод строки, поэтому может понадобиться сделать дополнительный вызов getline, чтобы его съесть.

stringstream ss("5\na b c");
int n;
string s;
ss >> n;
getline(ss, s); // ест перевод строки после 5
getline(ss, s); // читает вторую строку
cout << n << " : " << s << endl; // 5 : a b c

<iomanip>: fixed, setprecision, setw, setfill, hex/dec

Заголовок <iomanip> содержит возможности форматирования, в подавляющем большинстве случаев заменяющие форматные строки printf.

Манипуляторы setprecision и fixed позволяют выставлять точность вывода вещественных чисел для всех последующих <<, указывая число всех цифр или цифр после запятой.

double n = 3.141592653;
cout << setprecision(5) << n << endl; // 3.1416
cout << fixed << setprecision(5) << n << endl; // 3.14159

Пара setw и setfill позволяет выводить строку или число на указанное число позиций, возможно, заполняя их чем-то непробельным.

cout << setw(8) << "hello" << endl; // "   hello"
cout << setfill('0') << setw(3) << 7 << endl; // "007"

Манипуляторы hex и dec позволяют выводить целые числа в шестнадцатеричной или десятичной системе счисления.

int n;
stringstream("2A") >> hex >> n;
cout << dec << n << endl; // 42
cout << hex << 42 << endl; // 2a

<iomanip>: noskipws/skipws

По умолчанию cin вводит несколько char, пропуская пробельные символы. Манипуляторы noskipws/skipws позволяют переключить это поведение.

char s1, s2, s3;
stringstream("a b c") >> s1 >> s2 >> s3;
cout << s1 << ", " << s2 << ", " << s3 << endl; // a, b, c
stringstream("a b c") >> noskipws >> s1 >> s2 >> s3;
cout << s1 << "," << s2 << "," << s3 << endl; // a, ,b

cin/cout.tie(0); cin/cout.sync_with_stdio(false); endl vs '\n'

Потоки ввода-вывода разрабатывались в расчете на интенсивное расширение и модификацию их состояния. Оверхед, вызванный этим, может привести к TL. В таких случаях может помочь магия вида

cin.tie(0);
cin.sync_with_stdio(false);

для объемного ввода, или такая же с cout для объемного вывода.

Как правило, в СП следует использовать << endl для перевода строки при выводе. Он аналогичен << '\n' << flush. Манипулятор flush выводит все из буфера в вывод, при выводе очень большого количества строк это изрядно тормозит. В этом случае стоит заменить все endl на "\n", оставив в конце endl или flush.

<cstdio>: printf/scanf для жирных инпутов

Если заставить потоки ввода-вывода зайти в TL никак не получается (только если дело именно в этом и только из-за этого), можно использовать сишные функции.

int n;
long long n_l;
double d;
float f;
char s[5];
char ch;
scanf("%d %lld %lf %f %s %c", &n, &n_l, &d, &f, &s, &ch);
printf("%d %lld %lf %f %s %c", n, n_l, d, f, s, ch);

<vector>

Вместо массивов в программах на C++ следует всегда использовать последовательный контейнер vector. Его размер задается в конструкторе. Можно задать значение каждого элемента, по умолчанию будет дефолтное (пустой vector, 0, "", false).

vector<int> v(5); // {0,0,0,0,0}
vector<vector<int>> v(2, vector<int>(3, -1)); // {{-1,-1,-1}, {-1,-1,-1}}

Если нужно выставить размер и заполняющее значение после создания

vector<double> v;
v.assign(4, 1.0); // {1.0, 1.0, 1.0, 1.0}

Вектор можно инициализировать списками инициализации или из пары итераторов.

vector<int> v{1, 2, 3, 4, 5};
vector<int> v2(v.begin() + 2, v.begin() + 4); // {3, 4}

Обращение к элементу вектора как у массива.

cout << v2[0]; // 3

Вектор имеет почти ту же производительность, что и массив, поэтому в release он не проверяет границы массива. Можно заставить его это делать (и кидать исключение при нарушении):

cout << v2.at(2); // Exception: out_of_range

clean != empty

Очистить (не путать с проверить v.empty() (а есть такие, кто путает?)), работает для любого контейнера.

v.clear();

begin, end, rbegin, rend

Есть несколько способов проитерироваться по контейнеру (пример для vector):

vector<int> v{1, 2, 3}

// По индексу
for (int i = 0; i < v.size(); ++i) {
    cout << v[i] << endl;
}

// По итераторам
// auto = vector<int>::iterator
for (auto it = v.begin(); it != v.end(); ++it) {
    cout << *it << endl;
}

// Рекомендуемый: С++11 range-based for
for (int item : v) {
    cout << item << endl;
}

Контейнер можно обойти и в обратном порядке.

// auto = vector<int>::reverse_iterator
for (auto it = v.rbegin(); it != v.rend(); ++it) {
    cout << *it << endl;
}

push_back, pop_back, emplace_back, front, back

Вектор это динамический массив, ему в конец можно добавлять за амортизированную O(1) новые элементы (push_back) , меняя размер (size). Чтобы такая сложность соблюдалась, вектор выделяет больше памяти, чем нужно (сколько именно — capacity), а при достижении лимита (.size() == .capacity()) увеличивает размер сразу в 1.5-2 раза (пример для MSVC), копируя старые элементы (что портит все итераторы).

vector<int> v;
for (int i = 0; i < 16; ++i) {
    v.push_back(123);
    cout << v.size() << "-" << v.capacity() << " ";
}
// 1-1 2-2 3-3 4-4 5-6 6-6 7-9 8-9 9-9 10-13 11-13 12-13 13-13 14-19 15-19 16-19

Если объект для вставки нужно сначала создать (например, пару), конструктор и push_back можно объединить в один вызов, экономящий копирование.

vector<pair<int, string>> v;
// Вместо v.push_back(make_pair(5, "hello"));
v.emplace_back(5, "hello");

Кроме добавления в конец, с конца можно и удалять элементы.

vector<int> v{1, 2, 3};
v.pop_back(); // {1, 2}

К первому и последнему элементу можно обращаться по ссылке.

vector<int> v{2, 4, 8, 16, 32};
cout << v.front() << endl; // 2
cout << v.back() << endl; // 32
v.back() = -1; // {2, 4, 8, 16, -1}

insert

По произвольному итератору можно вставить значение или отрезок из пары итераторов, при этом все элементы после итератора копируются за O(N).

vector<int> v{1, 2, 3};
vector<int> w{5, 6};
v.insert(v.begin() + 1, w.begin(), w.end()); // {1, 5, 6, 2, 3}
v.insert(v.begin() + 2, 8); // {1, 5, 8, 6, 2, 3}

size, resize, capacity, reserve, swap hack/shrink_to_fit

У существующего вектора можно изменить размер

vector<int> v{1, 2, 3};
v.resize(5, -1); // {1, 2, 3, -1, -1}

или емкость (полезно, чтобы избежать времязатратного большого количества копирований элементов вектора, если верхняя оценка их количества известна заранее).

cout << v.size() << " " << v.capacity() << endl; // 5 5
v.reserve(1000);
cout << v.size() << " " << v.capacity() << endl; // 5 1000

С помощью reserve емкость можно изменить только вверх, но можно пересоздать вектор с существующими элементами и минимальной емкостью одной строкой (так называемый swap hack). Это может быть полезно, если суммарный размер векторов в каждый момент ограничен, но суммарный максимальный слишком велик.

v.swap(vector<int>(v));
cout << v.size() << " " << v.capacity() << endl; // 5 5

Тот же эффект имеет метод .shrink_to_fit(), введенный в C++11.

vector<bool>

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

<string>

Вместо zero-terminated C-строк в программах на C++ следует всегда использовать string.

string s = "hello, world!";
char c = s[6]; // аналогично вектору s.at(6);
cout << s << endl; 
s += c; s += s; // Конкатенация: "hello, world! hello, world! "

string(10, ' '), std::string("a") + "b"

Конструктор string, как и у vector, позволяет указывать число элементов и сам элемент.

cout << string(5, '!') << endl; // "!!!!!"

Для совместимости с C строковый литерал "a" это char const *, + их не конкатенирует.

string s = "AaBb";
s += string("C") + "c"; // s += "C" + "c" дает compilation error
cout << s << endl; // AaBbCc

В С++14 появился литерал, создающий строки.

string s = "a"s + "b";

length/size, substr

Аналогично vector, string имеет методы assign, clear, empty, begin, end, rbegin, rend, size, resize, capacity, reserve. Синонимом для size служит length.

string t = "Hedgehog is gonna get out from that jail";
cout << t.length() << endl; // 40

Подстрока (начало, длина):

cout << t.substr(18, 3) << endl; // "get"

push_back

Аналогично vector, string имеет методы, push_back, pop_back, front, back, insert.

string s;
for (int i = 0; i < 10; ++i) {
    s.push_back('a' + i);
}
cout << s << endl; // abcdefghij

to_string, stoi

Числовые типы можно преобразовать в строку to_string и обратно семейством stoi/stoll/stoull/stof/stod.

double pi = 3.14159265;
string s = "Pi = " + to_string(pi);
cout << s << endl; // Pi = 3.141593

s = "12345678901";
//cout << stoi(s) << endl; // Exception: out_of_range
cout << stoll(s) << endl; // 12345678901

find, rfind, find_*_of, string::npos

В string можно искать подстроки (тривиальным алгоритмом за O(NM)). Необязательный второй аргумент — смещение, с которого начинать поиск. Если подстроки нет, возвращается string::npos.

string s = "hello, world!";
//          0123456789012
cout << s.find("wo") << endl; // 7
cout << boolalpha << (s.find("hi") == string::npos) << endl; // true

Поиск с конца (найденная подстрока будет иметь начало не правее смещения):

cout << s.rfind("l", 9) << endl; // 3

Такой цикл найдет все вхождения подстроки

size_t off = 0;
while (true) {
    off = s.find("l", off);
    if (off == string::npos) { break; }
    cout << off << endl; // 2 3 10
    off += 1;
}

Кроме подстрок, можно искать символы из некоторого множества методом find_first_of. Аналогично find_first_not_of ищет символы, не принадлежащие множеству, а find_last_of и find_last_not_of ищут такие символы с конца строки.

cout << s.find_last_of("aeiou") << endl; // последняя гласная на позиции 8

<sstream>: stringstream ss("str"), ss.str()

Строковый поток ввода-вывода аналогичен cin/cout, но работает не с stdin/stdout, а со строкой.

stringstream ss;
ss << 2 << " " << 4 << " " << 8;
string s = ss.str();
cout << s << endl; // "2 4 8"

stringstream ss("1 2 3");
int n1, n2, n3;
ss >> n1 >> n2 >> n3;
cout << n1 << " " << n2 << " " << n3 << endl; // 1 2 3

<cctype>

isalpha, isalnum, isblank, isdigit, islower, isupper, isxdigit

В СП чаще всего полезны эти классы символов, список из 0-127:

  • isalpha — A-Za-z
  • isalnum — 0-9A-Za-z
  • isblank — \t и пробел
  • isdigit — 0-9
  • islower — a-z
  • isupper — A-Z
  • isxdigit — 0-9A-Fa-f

tolower, toupper, использование совместно с transform

Ожидаемо преобразуют A-Z в a-z и наоборот. Строки можно преобразовать этими функциями, используя transform из <algorithm>.

string s = "where is STL?!";
transform(s.begin(), s.end(), s.begin(), toupper);
cout << s << endl; // WHERE IS STL?!

<deque>

Дек подобен вектору, но в него можно добавлять/удалять элементы с обоих концов за O(1). Внутри это циклический буфер переменного размера с указателями на отрезки элементов равной длины.

deque<int> d;
d.push_back(3);
d.push_front(2);
d.push_back(4);
d.push_front(1);
d.push_back(5);
for (int i = 0; i < d.size(); ++i) {
    cout << d[i] << " ";
}
cout << endl; // 1 2 3 4 5

На основе deque построены std::stack и std::queue, которые просто оставляют обернутый deque без лишних методов.

<queue>: priority_queue

Очередь с приоритетами позволяет за O(logN) вставлять элементы, и за O(1) получать максимальный элемент в коллекции, за O(logN) удалять его. Внутри это бинарная куча на векторе, поддерживающая инвариант для всех i A[i] >= A[2*i + 1] && A[i] >= A[2*i + 2].

priority_queue<int> pq;
for (int i = 0; i < 5; ++i) {
    pq.push(i);
}
while (pq.size()) {
    int item = pq.top();
    cout << item << " ";
    pq.pop();
}
cout << endl; // 4 3 2 1 0

Обычно очередь с приоритетами используют над парами (приоритет, задание), откуда она и получила свое название.

priority_queue<pair<int, char>> pq;
for (int i = 0; i < 5; ++i) {
    pq.emplace(i, 'a' + i);
}
cout << pq.top().second << endl; // e

<tuple>: pair, make_pair, .first/.second; tuple, make_tuple, get<#>();

Два или более связанных значения можно объединить в пару или кортеж. Доступ к элементам пары через поля:

pair<int, int> p(1, 2);
cout << p.first << " " << p.second << endl; // 1 2
p = make_pair(14, 28);
cout << p.first << " " << p.second << endl; // 14 28

к элементам кортежа шаблонной функцией:

tuple<int, int, int> tp(1, 2, 3);
cout << get<0>(tp) + get<1>(tp) + get<2>(tp) << endl; // 6
tp = make_tuple(14, 28, 42);
cout << get<0>(tp) + get<1>(tp) + get<2>(tp) << endl; // 84

Лексикографическое сравнение

Для последовательных контейнеров (vector, string, deque, pair, tuple) в STL определен оператор <, сравнивающий их лексикографически (сначала по первому элементу, если равны, по второму, и так далее), а значит, их можно сравнивать, а контейнеры из них — сортировать.

Сравнение векторов:

vector<int> box1(3), box2(3);
for (int i = 0; i < 3; ++i) { cin >> box1[i]; }
for (int i = 0; i < 3; ++i) { cin >> box2[i]; }

sort(box1.begin(), box1.end());
sort(box2.begin(), box2.end());

if (box1 <= box2) {
    cout << "You can put the first box into the second one" << endl;
} else if (box2 <= box1) {
    cout << "You can put the second box into the first one" << endl;
} else {
    cout << "You can't put one box into another" << endl;
}

Сравнение строк:

cout << boolalpha << (string("a") < string("abcd")) << endl; // true
cout << boolalpha << (string("a") < string("ABCD")) << endl; // false

Сравнение пар:

cout << boolalpha << (make_pair(1, 2) < make_pair(1, 3)) << endl; // true

<map>, <set>

map, сортированность ключей

В STL есть ассоциативный контейнер map (словарь), позволяющий сопоставлять ключу любого типа, поддерживающего operator <, значение произвольного типа. Внутри он реализован на основе почти сбалансированного бинарного красно-черного дерева, поэтому поиск по ключу занимает O(logN) сравнений, вставка и удаление O(logN). Красно-черное дерево упорядочено по ключам, ключи уникальны.

[key]= vs at, for (auto kv : mapa) { }

Вызов оператора [] автоматически создает дефолтным конструктором значение, если такого ключа раньше не было. Поэтому для константных map вместо оператора [] надо использовать метод at, бросающий исключение out_of_range при отсутствии ключа.

Итерация по map дает pair<TKey, TValue>.

map<char, int> m;
for (char ch : string("hello, world!")) {
    m[ch] += 1;
}
cout << m.size() << endl; // 10
for (auto kv : m) {
    cout << kv.first << "-" << kv.second << " ";
} //  -1 !-1 ,-1 d-1 e-1 h-1 l-3 o-2 r-1 w-1

count, erase

Проверить наличие ключа в map можно, либо сравнивая m.find(key) (возвращает итератор) с m.end(), либо воспользовавшись методом count.

map<char, int> m{{'a', 1}, {'c', 1}, {'b', 0}, {'d', 2}, {'f', 1}};
cout << m.count('a') << " " << m.count('e') << endl; // 1 0

Удалять из map можно методом erase, который может принимать и ключ, и итератор, и отрезок, заданный двумя итераторами.

m.erase('c'); // {'a': 1, 'b': 0, 'd': 2, 'f': 1}
m.erase(m.find('f')); // {'a': 1, 'b': 0, 'd': 2}

set, insert

Контейнер set (множество) подобен map, только без значений и, следовательно, без []. Вставку делает метод insert (как элемента, так и отрезка итераторов).

set<int> s{1, 2, 3, 5, 6};
cout << s.count(1) << " " << s.count(4) << endl; // 1 0

cout << s.size() << endl; // 5
s.insert(2);
cout << s.size() << endl; // 5
s.insert(0);
cout << s.size() << endl; // 6

vector<int> add{6, 7, 8};
s.insert(add.begin(), add.end());

s.erase(7);

for (int item : s) {
    cout << item << " "; // 0 1 2 3 5 6 8
}

<unordered_set>, <unordered_map>

В STL реализована открытая хэш-таблица, позволяющая вставку и поиск ключа за амортизированную O(1). Ее реализация опирается на std::list, хранящий все вставленные элементы в порядке обхода контейнера, и указатели внутрь этого списка на голову и хвост b = 2n бакетов в векторе длины 2b. Число бакетов поддерживается не меньшим, чем число элементов. При исчерпании размера происходит изменение числа бакетов в 2 раза (в MSVC при маленьком размере хэш-таблицы сразу в 8 раз) и пересчет хэша std::hash для всех элементов.

Контейнеры unordered_map и unordered_set подобны map и set, но ключи отсортированы по hash % u.bucket_count().

unordered_set<char> u;
for (int i = 0; i < 26; ++i) {
    u.insert('a' + i);
}
for (char ch : u) {
    cout << ch;
} // iabcdefghjklmnopqrstuvwxyz

std::hash<T>::operator()

Функция hash реализована для многих типов как xor с очередным байтом и умножение в цикле. Но для многих полезных типов вроде кортежей, hash придется специализировать самостоятельно:

namespace std {
template<typename T1, typename T2> struct hash<pair<T1, T2>> {
    size_t operator () (pair<T1, T2> const& arg) const {
        return hash<T1>()(arg.first) ^ hash<T2>()(arg.second);
    }
};
}

<algorithm>

В STL реализованы некоторые простые и часто используемые обобщенные алгоритмы. Обобщенные они потому, что им обычно без разницы, с каким контейнером они работают, они принимают пару итераторов.

min, max, minmax, max_element, min_element

Минимум, максимум, оба сразу:

cout << min(123, 456) << " " << min('a', 'b') << endl; // 123 a
cout << max(2.5, 2.6) << " " << max('k', 'o') << endl; // 2.6 o
pair<int, int> res = minmax({ 2, 4, 8, 16, 32 });
cout << res.first << ' ' << res.second << endl; // 2 32

Максимум в последовательности (аналогично min_element), возвращает итератор:

vector<int> v{1, 2, 3, 4, 5};
cout << max_element(v.begin(), v.end()) - v.begin() << endl; // индекс 4
cout << *max_element(v.begin(), v.end()) << endl; // значение 5

sort, предикат с tie, stable_sort, is_sorted

Сортировка:

vector<int> v{2342, 1231, 87978, 123, 789};
sort(v.begin(), v.end()); // 123 789 1231 2342 87978

в обратном порядке:

sort(v.rbegin(), v.rend()); // 87978 2342 1231 789 123

с предикатом для сравнения:

vector<int> v{-2, -1, 0, 1, 2, 3};
sort(v.begin(), v.end(), [](int a, int b) {
    return abs(a) < abs(b);
}); // 0 -1 1 -2 2 3

с предикатом для лексикографического сравнения (tie создает кортеж ссылок); пример сортирует буквы сначала по частотности (по убыванию), затем по коду символа (по возрастанию):

string s = "hello, world!";
map<char, int> m;
for (char ch : s) { m[ch] += 1; }
vector<pair<char, int>> v(m.begin(), m.end());
sort(v.begin(), v.end(), [](pair<char, int> const& a, pair<char, int> const& b) {
    return tie(-a.second, a.first) < tie(-b.second, b.first);
}); // {{'l', 3}, {'o', 2}, {' ', 1}, {'!', 1}, {',', 1}, {'d', 1}, {'e', 1}, {'h', 1}, {'r', 1}, {'w', 1}}

Стабильная сортировка не меняет исходный порядок равных с точки зрения предиката символов.

vector<pair<char, int>> v(m.rbegin(), m.rend());
stable_sort(v.begin(), v.end(), [](pair<char, int> const& a, pair<char, int> const& b) {
    return -a.second < -b.second;
}); // {{'l', 3}, {'o', 2}, {'w', 1}, {'r', 1}, {'h', 1}, {'e', 1}, {'d', 1}, {',', 1}, {'!', 1}, {' ', 1}}

Проверить, что последовательность уже отсортирована:

vector<int> v{1, 2, 3, 1};
cout << boolalpha << is_sorted(v.begin(), v.end()) << endl; // false
sort(v.begin(), v.end());
cout << boolalpha << is_sorted(v.begin(), v.end()) << endl; // true

sort/iota + next_permutation

Функция next_permutation позволяет перебирать перестановки (возвращая false, если текущая перестановка лексикографически максимальна). В СП, как правило, перебирают перестановки индексов, в этом случае исходная последовательность обычно создается iota. Если же нет, почти всегда следует сначала взять лексикографически минимальную перестановку объектов, использовав sort.

vector<int> v(4);
iota(v.begin(), v.end(), 1);
do {
    cout << v[0] << v[1] << v[2] << v[3] << endl;
} while (next_permutation(v.begin(), v.end()));
// 1234; 1243; 1324; 1342; 1423; 1432; 2134; 2143; 2314; 2341; 2413; 2431;
// 3124; 3142; 3214; 3241; 3412; 3421; 4123; 4132; 4213; 4231; 4312; 4321;

unique/remove/remove_if + .erase

Обобщенные алгоритмы умеют переставлять местами элементы, но не умеют их удалять, за это отвечает сам контейнер. Алгоритм unique ищет не первые повторяющиеся элементы и переставляет их в конец. Чтобы unique давал действительно уникальные элементы, последовательность сначала надо отсортировать. Алгоритмы remove/remove_if переставляют в конец определенное значение или значения, удовлетворяющие предикату. Они возвращают итератор на начало этого конца, который можно использовать для его удаления методом erase контейнера.

vector<int> v = {1, 1, 2, 3, 3, 3, 1, 1, 2, 2};
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end()); // 1 2 3
v.erase(remove_if(v.begin(), v.end(), [](int x) {
    return x % 2 == 0;
}), v.end()); // 1 3

reverse

Обратить элементы последовательного контейнера:

string s = "desserts";
reverse(s.begin(), s.end());
cout << s << endl; // stressed

fill, copy, copy_n, <iterator>: back_inserter, istream_iterator

Целый ряд функций предназначен для заполнения контейнеров элементами из какого-нибудь источника. Каждый раз, когда вы используете memset, в мире умирает котенок. Функции back_inserter и inserter создают итератор вставки, который вызывает push_back и insert соответственно у контейнера-аргумента при попытке записи по нему.

vector<int> a(5); // {0, 0, 0, 0, 0}
fill(a.begin() + 1, a.end(), -1); // {0, -1, -1, -1, -1}
copy(a.begin(), a.begin() + 2, a.begin() + 2); // {0, -1, 0, -1, -1}
vector<int> b;
copy_n(a.rbegin(), 3, back_inserter(b)); // {-1, -1, 0}

В целях универсальности STL содержит класс итератора (только для чтения или только для записи) для потоков ввода-вывода. Дефолтный конструктор istream_iterator позволяет дочитать до EOF.

stringstream ss("5\n1 2 3 4 5\n1 1 2 3 5");
int n;
ss >> n;
vector<int> v, w;
copy_n(istream_iterator<int>(ss), n, back_inserter(v)); // v = {1, 2, 3, 4, 5}
copy(istream_iterator<int>(ss), istream_iterator<int>(), back_inserter(w)); // w = {1, 1, 2, 3, 5}
copy(w.begin(), w.end(), ostream_iterator<int>(cout, ", ")); cout << endl; // 1, 1, 2, 3, 5, 

most vexing parse

Редко, но может встретиться неприятная неоднозначность (так называемый most vexing parse), когда программист думает, что w это объявление переменной, принимающей в конструктор два объекта, а компилятор, что это прототип функции.

vector<int> w(istream_iterator<int>(ss), istream_iterator<int>());

MSVC выдает варнинг вида

warning C4930: prototyped function not called (was a variable definition intended?)

Убедить компилятор, что это объявление переменной, можно скобками.

stringstream ss("1 2 3 4 5");
vector<int> w((istream_iterator<int>(ss)), istream_iterator<int>());
copy(w.begin(), w.end(), ostream_iterator<int>(cout, "_")); // 1_2_3_4_5_

find, find_if, count, count_if

Алгоритмы find/find_if позволяют найти в последовательности первое значение, равное заданному или удовлетворяющее предикату, а count/count_if посчитать, сколько таких всего.

vector<int> v{0, 1, 1, 2, 3, 5, 8, 13, 21, 34};
cout << find(v.begin(), v.end(), 8) - v.begin() << endl; // позиция 6
cout << *find_if(v.begin(), v.end(), [](int i) { return i > 10; }) << endl; // 13
cout << count(v.begin(), v.end(), 1) << endl; // 2
cout << count_if(v.begin(), v.end(), [](int i) { return i % 2 == 0; }) << endl; // 4

search

Алгоритм search расширяет string::find на произвольные последовательности.

vector<int> v{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6};
auto seq = {3, 5};
cout << search(v.begin(), v.end(), seq.begin(), seq.end()) - v.begin() << endl; // 9

includes, set_union, set_intersection, set_difference, set_symmetric_difference

Теоретико-множественные операции вычисляются над сортированными отрезками (чаще всего в векторах, потому что оверхед ниже).

Включение:

vector<int> v1{2, 8, 16, 32};
vector<int> v2{2, 4, 8};
vector<int> v3{8, 16};
cout << boolalpha << includes(v1.begin(), v1.end(), v2.begin(), v2.end()); // false
cout << boolalpha << includes(v1.begin(), v1.end(), v3.begin(), v3.end()); // true

объединение, пересечение, разность, симметрическая разность (требуют итератор для записи результата):

vector<int> v1{10, 20, 30, 40};
vector<int> v2{40, 50, 60, 70};
vector<int> res0111, res0001, res0100, res0110;

set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(res0111));
// 10 20 30 40 50 60 70
set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(res0001));
// 40
set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(res0100));
// 10 20 30
set_symmetric_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(res0110));
// 10 20 30 50 60 70

lower_bound/upper_bound

Целочисленный бинарный поиск ищет в отсортированном по возрастанию отрезке (в векторе за O(logN)) отрезок [begin, end[, содержащий это значение.

vector<int> v{1, 1, 1, 1, 2, 2, 2, 3, 3, 4};
cout << "2 in [" <<
    lower_bound(v.begin(), v.end(), 2) - v.begin() << "; " <<
    upper_bound(v.begin(), v.end(), 2) - v.begin() << "[" << endl; // 2 in [4; 7[

Если хочется вычислять «элементы» на лету по «индексу», можно использовать собственный класс итератора.

struct int_iterator : iterator<random_access_iterator_tag, int> {
    int n;
    function<int(int)> pred;
    int_iterator(int n, function<int(int)> pred) : n(n), pred(pred) { }
    int operator * () const { return pred(n); }
    operator int () const { return n; }
    int_iterator& operator ++ () { return *this += 1; }
    int_iterator& operator += (int rhs) { n += rhs; return *this; }
};
function<int(int)> pred = [](int x) {
    if (x < 100500) { return -1; }
    if (x > 100600) { return 1; }
    return 0;
};
int_iterator it_begin(0, pred), it_end(1000000, pred);
cout << "[" <<
    lower_bound(it_begin, it_end, 0) << ", " <<
    upper_bound(it_begin, it_end, 0) << "[" << endl; // [100500, 100601[

<iterator>: begin(cont), end(cont), size(cont)

Вместо методов контейнеров .begin()/.end()/.size() можно использовать глобальные функции begin(cont)/end(cont)/size(cont), которые поддерживают еще и C-массивы и C-строки.

cout << size("abcde") << endl; // 6 потому что nullchar

<numeric>: accumulate, partial_sum, iota

Сумма отрезка, заданного парой итераторов. Тип возвращаемого значения задается начальным значением суммы (суммируйте vector<int64_t> в 0LL).

vector<int> v{1, 2, 3, 4};
cout << accumulate(v.begin(), v.end(), 0) << endl; // 10

Префиксные суммы:

vector<int> v{1, 2, 3, 4, 5}, res(5);
partial_sum(v.begin(), v.end(), res.begin()); // 1 3 6 10 15

Генерация последовательных значений (префиксным ++):

vector<int> v(5);
iota(v.begin(), v.end(), -2); // -2 -1 0 1 2

<cmath>

Математических функций много, приведено популярное в СП и неочевидное подмножество.

hypot, atan2, pi = atan(1) * 4

L2-расстояние (гипотенуза прямоугольного треугольника), точнее, но медленнее наивного метода:

cout << hypot(4, 3) << endl; // 5

Выражение atan2(y, x) считает угол направления на (x,y) в ]−π, +π], арктангенс y/x, учитывающий знаки и не боящийся деления на 0:

cout << atan2(10, -10) << " radians" << endl; // 2.35619

Пи до сих пор нет в стандарте. Вместо использования компилятороспецифичных макросов или вбивания ручками можно использовать

double const pi = atan(1) * 4; // 3.1415926535897931
cout << setprecision(20) << pi << " " // 3.141592653589793116
    << nexttoward(pi, 3.0) << " "  // 3.1415926535897926719
    << nextafter(pi, 4.0) << endl; // 3.1415926535897935601

round, floor, ceil

Округление к ближайшему целому вниз (антье вниз):

cout << floor(2.7) << " " << floor(-2.5) << endl; // 2 -3

вверх:

cout << ceil(2.7) << " " << ceil(-2.5) << endl; // 3 -2

к ближайшему (полуцелые дальше от 0):

cout << round(2.7) << " " << round(-2.5) << endl; // 3 -3

abs

Абсолютное значение:

cout << abs(-10) << endl; // 10

<complex>

Комплексные числа в СП могут сократить некоторые 2D геометрические вычисления. Например, генерацию смещений координат на квадратной сетке к 4-соседям

complex<int> dir(1, 0);
for (int i = 0; i < 4; ++i) {
    cout << dir << " " << dir.real() << " + " << dir.imag() << "j" << endl;
    // (1,0) 1 + 0j; (0, 1) 0 + 1j; (-1, 0) -1 + 0j; (0, -1) 0 + -1j
    dir *= complex<int>(0, 1);
}

или площадь треугольника.

stringstream ss("1 1\n1 4\n5 1");
double x, y;
ss >> x >> y; complex<double> a(x, y);
ss >> x >> y; complex<double> b(x, y);
ss >> x >> y; complex<double> c(x, y);
complex<double> A = b - a, B = c - a;
double S = abs((conj(A) * B).imag()) / 2.0;
cout << S << endl; // 6

Не забывайте, что в военное время значение синуса может достигать четырех.

cout << sin(1.570796327 - 2.063437069i) << endl; // (4,7.94362e-10)

<limits>: numeric_limits<int>::max()

Для всяких INF-значений вместо прикинутых на глаз чисел вроде 100500 можно использовать максимальные и минимальные значения типа.

cout << numeric_limits<int64_t>::min() << endl; // -9223372036854775808
cout << numeric_limits<int64_t>::max() << endl; //  9223372036854775807

<random>

ГПСЧ редко используется в СП, но иногда рандомизированное решение сложно зачелленджить. По дефолту C++ использует mt19937.

default_random_engine generator;
generator.seed(0);
uniform_real_distribution<double> distribution(0.0, 1.0); // аналогично uniform_int_distribution<int>
double rnd = distribution(generator);
cout << rnd << endl; // 0.592845

<utility>: swap

Обменять объекты местами:

int x = 5, y = 3;
swap(x, y);
cout << x << " " << y << endl; // 3 5

<bitset>

Битовое значение известного размера может быть удобно вывести, используя bitset.

cout << bitset<10>(777) << endl; // 1100001001

<chrono>: std::chrono::high_resolution_clock::now()

Точно замерить время:

auto t0 = chrono::high_resolution_clock::now();
this_thread::sleep_for(1.0s);
auto t1 = chrono::high_resolution_clock::now();
cout << chrono::duration_cast<chrono::milliseconds>(t1 - t0).count() << endl; // 999
cout << chrono::duration<double>(t1 - t0).count() << endl; // 0.999376

<functional>

С появлением в C++11 лямбда-функций стало очень удобно писать каллбаки. Чтобы их сохранять в переменные или принимать в функции, полезно использовать шаблон function.

stringstream ss("6 5\n0 1\n0 2\n1 3\n1 4\n4 5");
int n, m;
ss >> n >> m;
vector<vector<int>> adjlist(n);
for (int i = 0; i < m; ++i) {
    int a, b;
    ss >> a >> b;
    adjlist[a].push_back(b);
    adjlist[b].push_back(a);
}

int time = 0;
function<void(int, int, function<void(int, int)>)> dfs =
    [&adjlist, &time, &dfs](int v, int from, function<void(int, int)> enter) {
        enter(v, time++);
        for (int nn : adjlist[v]) {
            if (nn != from) {
                dfs(nn, v, enter);
            }
        }
        time++;
    };

dfs(0, -1, [](int v, int time) {
    cout << "Entered " << v << " at time " << time << endl;
});
/*
Entered 0 at time 0
Entered 1 at time 1
Entered 3 at time 2
Entered 4 at time 4
Entered 5 at time 5
Entered 2 at time 9
*/

Compiler-specific: __builtin_popcount, __builtin_clz, __builtin_ctz, __gcd, __int128

В СП часто бывают полезны интринсики, считающие одним ассемблерным опкодом число установленных бит в числе (popcount), число нулей в бинарной записи числа слева (clz — count leading zeroes) и справа (ctz — count trailing zeroes). Интринсики компиляторо-специфичны, здесь приведены реализации для MSVC и GCC.

#if defined(_MSC_VER)
#include <intrin.h>
#define popcount __popcnt
#define popcount64 __popcnt64
#elif defined(__GNUC__)
#define popcount __builtin_popcount
#define popcount64 __builtin_popcountll
#endif

#if defined(_MSC_VER)
#include <intrin.h>
int clz(uint32_t x) { unsigned long result = -1; _BitScanReverse(&result, x); return 31 - result; }
int ctz(uint32_t x) { unsigned long result = -1; _BitScanForward(&result, x); return result; }
int clz64(uint64_t x) { unsigned long result = -1; _BitScanReverse64(&result, x); return 63 - result; }
int ctz64(uint64_t x) { unsigned long result = -1; _BitScanForward64(&result, x); return result; }
#elif defined(__GNUC__)
#define clz __builtin_clz
#define ctz __builtin_ctz
#define clz64 __builtin_clzll
#define ctz64 __builtin_ctzll
#endif

uint64_t num = 0x000000F000000000ULL;
cout << "popcount: " << popcount64(num) << endl; // 4
cout << "leading 0s: " <<  clz64(num) << " trailing: " << ctz64(num) << endl; // 24 36

uint32_t num2 = 0x000F0000;
cout << "popcount: " << popcount(num2) << endl; // 4
cout << "leading 0s: " << clz(num2) << " trailing: " << ctz(num2) << endl; // 12 16

В С++17 в <numeric> появился std::gcd, но раньше его не было. В GCC он был деталью реализации std::rotate, поэтому доступен под именем __gcd. В MSVC его можно взять в boost.

#if defined(_MSC_VER)
#include <boost/math/common_factor.hpp>
using boost::math::gcd;
#elif defined(__GNUC__)
#define gcd __gcd
#endif

cout << gcd(2983479376572795LL, 29837483726583645LL) << endl; // 15

В 64-битном GCC существует расширение компилятора __int128, в MSVC его тоже придется брать из boost.

#if defined(_MSC_VER)
#include <boost/multiprecision/cpp_int.hpp>
typedef boost::multiprecision::int128_t int128_t;
#elif defined(__GNUC__)
typedef __int128 int128_t;
#endif

int128_t result = int128_t(2983479376572795LL) * 29837483726583645LL;
cout << int(result % 1000000007) << endl; // 493398412
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment