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 existsA box created without being filled contains a garbage value, not zero:
int x;
cout << x << "\n"; // unpredictable number, and may differ on each runThe 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: 4000000000The 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"; // -2147483648The 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; // 2500000000The 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.5The 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 digitThe 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.33fixed 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; // correctThe 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.
intis safe up to about ±2 × 10⁹; above that uselong 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 % 10andn / 10are the pair for processing digits.doubleis 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.
fixedandsetprecision(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.