03. Variables, data types, and input

Useful programs work with data that changes. This chapter introduces variables, the data types used in contests, their arithmetic operations, and how to read input in the format accepted by online judges.

Variables and types

In C++ every variable is given a type when it is created. The type determines which values it may hold and how much memory it takes.

int umur = 15;
long long penduduk = 8000000000LL;
double berat = 47.5;
char nilai = 'A';
bool lulus = true;
string nama = "Budi";

Think of a variable as a labeled box in memory. The label is its name, its size is determined by its type, and its contents can be replaced at any time — but its type cannot.

There are two different events that are often confused:

int umur = 15;   // declaration: a new box is created, then filled
umur = 16;       // assignment: an existing box, its contents replaced
int umur = 17;   // error: a box with that name already exists

A box created without being filled contains a garbage value, not zero:

int x;
cout << x << "\n";   // unpredictable number, and may differ on each run

The compiler does not always warn you. Make a habit of filling every variable when it is created, for example int jumlah = 0; — especially accumulator variables that will be added to inside a loop later.

Naming rules: letters, digits, and underscores are allowed, but a name may not start with a digit and may not be a C++ keyword such as int or return. Names are case-sensitive, so nilai and Nilai are two different boxes.

Types you need to master for OSN:

Type Holds Approximate range
int integer −2,147,483,648 … 2,147,483,647 (±2 × 10⁹)
long long large integer ±9.2 × 10¹⁸
double fractional number ±1.7 × 10³⁰⁸, 15–16 significant digits
char a single character 'A', 'z', '7'
bool true or false true or false
string text needs #include <string>

This is the most frequent source of zero scores at OSN: a computed result exceeds the range of int, and the value "wraps around" to a negative number without any error message. Rule of thumb: if the result may be more than 2 × 10⁹, use long long.

int a = 2000000000;
int b = a + a;            // overflows, result is negative
long long c = 2000000000LL + 2000000000LL;   // correct: 4000000000

The LL suffix tells the compiler that the number itself is a long long, not an int that is later stored into a long long.

Why overflow produces a negative number

An int occupies 4 bytes, i.e. 32 bits, and one bit is used for the sign. Only numbers from −2,147,483,648 to 2,147,483,647 fit. When a computed result goes past the upper end, the value does not stop there but wraps around to the lower end, just like a clock hand that passes 12 and comes back to 1:

int x = 2147483647;      // largest int value
cout << x + 1 << "\n";   // -2147483648

The two examples that most often ruin answers in contests:

Computation Correct answer Result when stored in int
2000000000 + 2000000000 4,000,000,000 −294,967,296
50000 * 50000 2,500,000,000 −1,794,967,296
1 + 2 + … + 1,000,000 500,000,500,000 1,784,293,664

Look at the second row: 50000 itself is very small, but its product is not. What matters is the size of the result, not the size of the input.

There is one more trap. The type of a multiplication result is determined by the types of its two operands, not by the type of the destination box:

int a = 50000, b = 50000;
long long salah = a * b;                  // -1794967296: overflows before being copied
long long benar = (long long)a * b;       // 2500000000

The multiplication a * b is computed first as an int, overflows there, and only then is the already-broken result copied into the long long. Applying a cast to one side makes the whole multiplication be done as long long.

A cheap habit that saves a lot of points: when in doubt, use long long. A program that uses long long for all integers is only slightly slower and uses slightly more memory, while a program with the wrong type scores zero.

Arithmetic

Operator Meaning Example Result
+ add 7 + 2 9
- subtract 7 - 2 5
* multiply 7 * 2 14
/ divide 7 / 2 3
% remainder (modulo) 7 % 2 1

Note that 7 / 2 gives 3, not 3.5. If both sides are integers, C++ uses integer division: the fractional part is discarded. To get 3.5, at least one side must be fractional:

cout << 7 / 2 << endl;        // 3
cout << 7 / 2.0 << endl;      // 3.5
cout << (double)7 / 2 << endl;// 3.5

The form (double)7 is called a cast: it forces a value to be read as another type.

Integer division truncates toward zero, so 7 / 2 becomes 3 and -7 / 2 becomes -3 (not -4).

double stores fractional numbers as binary approximations, so the values are not always exact:

cout << fixed << setprecision(17) << 0.1 + 0.2 << "\n";
0.30000000000000004

As a result, never compare two double values with ==: 0.1 + 0.2 == 0.3 is false. If comparing fractional values is really necessary, check their difference: if (fabs(a - b) < 1e-9) (fabs is in <cmath>). Better still, avoid double when the problem can be solved with integers — and most OSN problems can.

The % operator is for integers only, and it is used very often:

cout << 17 % 5 << endl;   // 2
cout << 10 % 2 << endl;   // 0  -> 10 is even
cout << 123 % 10 << endl; // 3  -> last digit
cout << 123 / 10 << endl; // 12 -> drop the last digit

The last two lines are a trick used again and again in OSN problems to process a number digit by digit.

For negative numbers, C++ makes the result of % follow the sign of the dividend: -7 % 3 is -1, not 2. Chapter 14 discusses the consequences and how to fix it.

Order of operations

As in mathematics, *, /, and % are evaluated before + and -. Operators of the same level are evaluated from left to right.

cout << 2 + 3 * 4 << "\n";      // 14, not 20
cout << (2 + 3) * 4 << "\n";    // 20
cout << 100 / 10 / 2 << "\n";   // 5  (read as (100/10)/2)

In contests, the rule of thumb is simple: when in doubt, add parentheses. Extra parentheses do not slow the program down at all, while the wrong order changes the answer.

Compound assignment

int x = 10;
x += 5;    // same as x = x + 5   -> 15
x -= 3;    // 12
x *= 2;    // 24
x /= 5;    // 4   (integer division)
x %= 3;    // 1
x++;       // 2   (add one)
x--;       // 1   (subtract one)

Reading input with cin

cin >> x reads one value from standard input and stores it in x. Spaces, tabs, and newlines are all treated as separators.

int a, b;
cin >> a >> b;
cout << a + b << endl;

Think of the input as one long queue of characters. Each cin >> x does three things in order: it skips all the spaces, tabs, and newlines at the front; it reads the following characters as long as they still make sense for the type of x; then it stops right before the next separator and leaves it in the queue.

Because spaces and newlines are treated the same, that program accepts 3 4 as well as:

3
4

Both are the same to cin.

The reading order must match exactly the order promised by the problem. If the problem says "the first line contains n, the second line contains n numbers", then n is read first, then the rest — and the number of cin >> operations executed must be exactly the number of values available. One extra cin >> makes the program wait for input that will never come.

cin >> x with x of type int will fail if what is available in the queue is not a number. When it fails, x is not filled and all subsequent reads fail as well — usually this shows up as a program that prints garbage numbers or prints nothing at all. If your output is strange from the start, first check whether the reading order matches the problem's input format.

Input and output format for the judge

At OSN, programs are graded by a machine. That is why there are strict rules:

  • Do not print prompt sentences such as Masukkan dua bilangan: ("Enter two numbers: "). The judge compares your output character by character; an extra sentence makes the answer count as wrong.
  • Print exactly what the problem asks for, with no additional text.
  • Trailing spaces or newlines are usually tolerated, but do not rely on it.

So for the problem "read two numbers, print their sum", the correct answer is exactly:

#include <iostream>
using namespace std;

int main() {
    int a, b;
    cin >> a >> b;
    cout << a + b << "\n";
    return 0;
}

When you run it on your own computer, type the numbers and then press Enter; the screen will look blank until you have entered all the numbers requested. That is normal.

Open exercises/03/03-masukan.cpp, compile it, then run it and type 10 3 followed by Enter. Look at the results of / and % for those two numbers.

Reading a line of text

cin >> nama stops at the first space, so Budi Santoso is read only as Budi. To read a whole line, use getline:

string baris;
getline(cin, baris);

If getline is used after cin >> n, the first line it reads is often empty: cin >> leaves the newline character in the input. The fix: call cin.ignore(); before getline.

Reading until the input runs out

Some problems do not tell you how many numbers there are. The standard pattern:

int x;
while (cin >> x) {
    // process x
}

cin >> x evaluates to false when the input has run out, so the loop stops by itself.

Printing fractional numbers

By default cout prints a double with six significant digits. Problems often ask for a specific number of digits after the decimal point:

#include <iomanip>

double rata = 7.0 / 3.0;
cout << fixed << setprecision(2) << rata << endl;   // 2.33

fixed means "count the digits after the decimal point", and setprecision(2) sets it to two digits. Both need to be written only once; their effect applies to all subsequent printing.

Open exercises/03/04-pecahan.cpp. Change setprecision(2) to setprecision(6), recompile, and compare the output.

Homework

Problem 1 — Sum of two numbers

Open exercises/03/homework/01-jumlah-dua.cpp. Read two integers from standard input and print their sum. No prompt sentence of any kind. This is the easiest form of problem on an online judge — make sure you can submit it correctly.

Problem 2 — Average of three scores

Open exercises/03/homework/02-rata-rata.cpp. Read three integers and print their average with two digits after the decimal point. Watch out for integer division.

Problem 3 — Convert seconds

Open exercises/03/homework/03-detik.cpp. Read one integer containing a number of seconds, and print it in the form hours minutes seconds separated by spaces. Example: input 3725 produces 1 2 5. Use / and %.

Problem 4 — Last digit and the rest

Open exercises/03/homework/04-digit.cpp. Read one positive integer and print two lines: its last digit, then the number without its last digit. Example: input 4071 produces 1 and then 407.

Challenge — Detecting overflow

Open exercises/03/homework/05-luapan.cpp. The file contains a multiplication of two large numbers whose result is wrong because it is stored in an int. Run it first, note the wrong result, then fix it with long long so that the output is correct. Write the results before and after the fix as a comment at the top of the file.

Most common mistakes

What was written Consequence
int for a result exceeding 2 × 10⁹ negative answer without any error message
long long x = a * b; with a, b of type int overflows before being copied; add a cast
int rata = jumlah / n; fraction discarded; use (double)jumlah / n
if (a == b) on two double values almost always wrong; compare the difference
cout << "Masukkan n: "; extra output makes the judge mark it wrong
getline right after cin >> n reads an empty line; call cin.ignore() first
variable used before being filled garbage value, result differs on each run

OSN tips

Read the constraints before writing code. The Constraints section of an OSN problem is not decoration: that is where the data type is decided. The order is always the same — look at the largest value that may appear, estimate the largest result, and only then choose the type. What matters is the size of the result, not the size of the input: two int numbers multiplied together can already exceed the int limit.

Constraint in the problem Safe type for the result
answer ≤ 2 × 10⁹ int
answer ≤ 9 × 10¹⁸ long long
answer is fractional double with setprecision

Overflow gives no error message. A program that overflows keeps running, keeps printing numbers, and is still judged Wrong Answer. If your answer suddenly turns negative on large-constraint tests even though the logic is correct, the first suspect is always int.

Watch out for half-way multiplication. Storing the result in a long long does not help if the multiplication itself is done as int:

int p = 1000000, l = 1000000;
long long luas = p * l;          // wrong: p * l is computed as int
long long benar = (long long)p * l;  // correct

The safest approach in a contest: if there is even a slight chance the result is large, declare the variable as long long from the start. The speed cost is negligible; the cost of a wrong answer is far higher.

Do not use double for integer answers. A double is only exact up to about 15 significant digits, so a large integer answer may be printed as 1e+18. Use double only when the problem actually asks for a fraction, and always with fixed << setprecision(k) as the problem requires.

The problem states how many decimal digits are required. If the problem asks for two digits after the decimal point, printing 82.5 is judged wrong even though the value is the same. fixed << setprecision(2) makes 82.5 print as 82.50.

Problems that ask for a fractional answer often include the sentence "the answer is considered correct if its difference from the judge's answer is no more than 10⁻⁶". That sentence means small rounding differences are tolerated — but the output format must still match. Read the output format section to the end before deciding on setprecision.

Summary

  • A variable is a labeled box; its type determines its contents and size.
  • int is safe up to about ±2 × 10⁹; above that use long long. What matters is the size of the result, not the size of the input.
  • / between two integers discards the fraction; % gives the remainder. n % 10 and n / 10 are the pair for processing digits.
  • double is not exact; do not compare it with ==.
  • cin >> skips all spaces and newlines, then reads one value.
  • A program for the judge reads from standard input and prints only the requested answer.
  • fixed and setprecision(k) from <iomanip> set the number of digits after the decimal point.

OSN-style exercises

The following three problems already use standard input, exactly like real problems. Test your answer by piping input from the terminal:

echo "10 7 3" | ./ubin

The starter files for all three are in exercises/03/osn/.

Problem 1 — Floor Tiles

A rectangular room measuring P × L centimeters will be covered with square tiles of side S centimeters. The tiles are laid starting from one corner of the room, parallel to the walls, and may not be cut. The remaining floor at the edges of the room that is not covered by whole tiles will be covered with cement.

Compute how many whole tiles are laid and how much floor area must be covered with cement.

Input format. One line containing three integers P, L, and S.

Output format. One line containing two integers: the number of whole tiles, then the remaining floor area in square centimeters, separated by one space.

Constraints.

  • 1 ≤ P, L ≤ 10⁹
  • 1 ≤ S ≤ 10⁹

Sample input

10 7 3

Sample output

6 16

Explanation. Along the length, 10 / 3 = 3 tiles fit; along the width, 7 / 3 = 2 tiles fit, so 3 × 2 = 6 tiles in total. The room area is 10 × 7 = 70, the covered area is 6 × 3 × 3 = 54, and the remainder is 70 − 54 = 16.

Starter file: exercises/03/osn/01-ubin-lantai.cpp

Problem 2 — Final Grade

The final grade of a subject is computed from three components with fixed weights: assignment score 30%, midterm exam (UTS) score 30%, and final exam (UAS) score 40%.

Input format. One line containing three integers: the assignment score, the UTS score, and the UAS score.

Output format. One line containing the final grade with exactly two digits after the decimal point.

Constraints. All three scores are between 0 and 100.

Sample input

80 75 90

Sample output

82.50

Explanation. 0.3 × 80 + 0.3 × 75 + 0.4 × 90 = 24 + 22.5 + 36 = 82.5. Since the problem asks for two digits after the decimal point, the answer is written 82.50, not 82.5.

Starter file: exercises/03/osn/02-nilai-akhir.cpp

Problem 3 — Arithmetic Sequence

An arithmetic sequence starts with first term a, and each subsequent term increases by b from the previous term. Determine the n-th term and the sum of the first n terms.

Input format. One line containing three integers a, b, and n.

Output format. One line containing two integers: the n-th term and the sum of the first n terms, separated by one space.

Constraints.

  • −10⁶ ≤ a, b ≤ 10⁶
  • 1 ≤ n ≤ 10⁶
  • Solve it without loops.

Sample input

3 5 4

Sample output

18 42

Explanation. The sequence is 3, 8, 13, 18. The fourth term is 18, and 3 + 8 + 13 + 18 = 42.

The ban on loops in this problem is not an OSN problem style — at OSN what is limited is running time, not how you write the code. The ban is there because loops are only covered in Chapter 05, and because the series formula really is the better answer: it stays fast even if n is raised to 10¹⁸.

Starter file: exercises/03/osn/03-deret-aritmetika.cpp

Confused, or already done? Open the homework solutions page.