The C++ Textbook

Part 10 · Problem solving

The contest template and fast I/O

The four lines every solution starts with, what they are worth, and the input shapes you will meet.

By the end of this chapter you can

  • Measure what C++ stream I/O costs and know when it matters
  • Read every input shape a contest uses, including one with no count
  • Write a template that does not get in your way

Every solution in this part starts the same way, and it is worth knowing what those lines actually buy before you copy them for the next forty chapters.

#include <bits/stdc++.h>          // everything, on GCC and Clang
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

}

Two of those four lines are performance, one is convenience, and one is a habit this book has spent nine parts arguing against. All four deserve a reason.

What sync_with_stdio(false) is worth

By default, C++ streams are kept synchronised with C’s stdio — every cin >> is coordinated with anything that might have used scanf, so that mixing them works. Almost nobody mixes them, and the coordination is not free.

One million integers, read three ways, best of three runs at -O2:

Time
cin >>, default settings 372 ms
cin >> after sync_with_stdio(false) and cin.tie(nullptr) 96 ms
scanf("%d") 118 ms

Nearly four times, for two lines. And note the third row: unsynchronised cin is faster than scanf here. The folklore that scanf is the fast option is out of date — it was true when the streams were slow, and what is actually slow is the synchronisation.

cin.tie(nullptr) is the second half. By default cin is tied to cout, meaning every read flushes pending output first — which is what makes an interactive prompt appear before the program waits. A contest program has nobody to prompt, and the flush per read is pure cost.

'\n' versus std::endl

std::endl writes a newline and flushes the stream. Flushing means a system call. Doing that once per line of a large output is the other common way to exceed a time limit.

300,000 lines of output:

To /dev/null To a file
std::endl 114 ms 210 ms
'\n' 18 ms 20 ms

Ten times, writing to a file. The stream flushes when it is destroyed at the end of main, so nothing is lost by not flushing yourself.

Use '\n'. Reach for std::endl only when you genuinely need the output to appear now — interactive problems, and debugging a program that crashes.

The input shapes

Four cover almost everything.

A count, then that many values. The common case.

int n;
cin >> n;
vector<int> a(n);
for (int& x : a) cin >> x;

Several test cases in one file. The first number is how many follow.

int tests;
cin >> tests;
while (tests--) {
    // read and solve one case
}

Values until the end of input, with no count given.

Reading until there is nothing left
#include <iostream>

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    long long value;
    long long total = 0;
    int count = 0;

    while (std::cin >> value) {      // false when extraction fails or EOF
        total += value;
        ++count;
    }

    std::cout << count << " values, sum " << total << '\n';
}

With no input at all — which is what this page gives it — that prints 0 values, sum 0, because the loop body never runs. That is the correct behaviour for an empty file, and it costs nothing to get right.

Lines, rather than whitespace-separated tokens. This is the one with a trap.

The getline trap
#include <iostream>
#include <sstream>
#include <string>

int main() {
    // Standing in for an input file containing "3\nhello world\n".
    std::istringstream input("3\nhello world\n");

    int n;
    input >> n;                       // reads 3, leaves the newline behind

    std::string first;
    std::getline(input, first);       // reads the rest of the line: nothing
    std::cout << "n = " << n << ", first getline: [" << first
              << "] length " << first.size() << '\n';

    std::string second;
    std::getline(input, second);      // now the line you wanted
    std::cout << "second getline: [" << second << "]\n";
}

cin >> n stops at the newline and leaves it in the buffer. The next getline reads from there to the end of that line, which is an empty string. The fix is to consume the rest of the line first:

cin >> n;
cin.ignore(numeric_limits<streamsize>::max(), '\n');   // discard to end of line
getline(cin, line);

or, more simply, use >> for everything when the input has no embedded spaces, and getline for everything when it does. Mixing them is what causes this.

#include <bits/stdc++.h>

A GCC and Clang implementation detail that includes the entire standard library in one line. It is not standard C++ and does not exist on MSVC.

It is right for a contest and wrong for everything else. In a contest you are optimising for the twenty seconds it takes to remember whether std::accumulate is in <numeric> or <algorithm>, and nobody will ever compile your file again. Chapter 7.6 measured what it costs — seven unused standard headers took an empty program from 35 ms to over a second to compile, and bits/stdc++.h is all of them — which matters enormously in a project and not at all for a file compiled once.

Every sample in this part includes what it uses, because they are teaching material and a reader should be able to see where a name comes from. Your contest template should use bits/stdc++.h. Both statements are true.

using namespace std;

Chapter 4.9 argued against this, and that argument stands for any code that lives longer than a submission: it drags every standard name into the global namespace, where it can collide with yours, and the collisions are found at the worst moment.

In a contest file the tradeoff genuinely reverses. Nothing else is in the file, nobody links against it, and sort(all(a)) beats std::sort(a.begin(), a.end()) when you are typing against a clock.

The one thing to know is which names it captures, because these bite:

Your name Collides with
count std::count
size std::size
data std::data
begin, end std::begin, std::end
next, prev std::next, std::prev
swap, max, min the obvious ones
y1, y0, j1 POSIX Bessel functions in <cmath>

That last row is the famous one: int y1; fails to compile on GCC with a message about a conflicting declaration, because <cmath> puts a function called y1 in the global namespace. Chapter 5.5’s authoring notes hit the same thing with gamma. Name your variables y_1, or anything else.

A template worth using

#include <bits/stdc++.h>
using namespace std;

using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int tests = 1;
    // cin >> tests;              // uncomment when the input has a case count

    while (tests--) {
        int n;
        cin >> n;

        vector<ll> a(n);
        for (ll& x : a) cin >> x;

        // solve

        cout << "\n";
    }
}

Short on purpose. Templates that arrive with two hundred lines of macros, a debug printer and a segment tree cost more than they save: you spend the first minute scrolling past code you are not using, and the macros make the compiler’s error messages worse at the moment you most need them.

The two things worth having beyond the above are using ll = long long;, because you will type it constantly, and the multi-test-case loop, because switching a solution to it under time pressure is exactly when mistakes happen.

Check yourself

Practice