Глиф Учебники

Урок 9. Задачи школьного курса

Курс «Pascal» · урок 9 из 9 · 4 минуты чтения

В этом уроке — задачи, которые встречаются почти в каждом школьном курсе информатики и на контрольных. Все они собраны из того, что уже было: div и mod, условия, циклы, строки. Сначала попробуйте решить задачу сами, а потом сверьтесь с разбором.

Цифры числа

Задача. Дано целое число. Сколько в нём цифр и чему равна их сумма?

Последняя цифра числа — n mod 10, а n div 10 отбрасывает её. Так повторяется, пока число не кончится:

Pascal
program Digits;
var
  n, sum, count: longint;
begin
  readln(n);
  n := abs(n);
  sum := 0;
  count := 0;
  repeat
    sum := sum + n mod 10;
    count := count + 1;
    n := n div 10;
  until n = 0;
  writeln('Цифр: ', count, ', сумма цифр: ', sum);
end.
Ввод
90210
Вывод
Цифр: 5, сумма цифр: 12
n n mod 10 sum count 9 0 2 1 0 0 0 1 9 0 2 1 1 1 2 9 0 2 2 3 3 9 0 0 3 4 9 9 12 5 0 until n = 0 — цикл закончен
Каждый шаг цикла берёт последнюю цифру числа 90210 через n mod 10, прибавляет её к сумме и отбрасывает через n div 10; когда n становится 0, сумма равна 12, а цифр насчитано 5.

repeat выбран не случайно: у числа 0 одна цифра, и тело цикла должно выполниться хотя бы раз. abs убирает минус, чтобы mod не давал отрицательных цифр. Тот же приём — произведение цифр, самая большая цифра, число наоборот. Подробнее — в справке Сумма цифр числа.

Простые числа

Задача. Вывести все простые числа от 2 до n. Простое число делится только на 1 и на себя.

Проверку удобно вынести в функцию. Делители достаточно перебирать, пока d * d <= x: если у числа есть делитель больше корня, то есть и парный ему меньше корня.

Pascal
program PrimesToN;
var
  n, i: integer;

function IsPrime(x: integer): boolean;
var
  d: integer;
begin
  IsPrime := x >= 2;
  d := 2;
  while d * d <= x do
  begin
    if x mod d = 0 then
    begin
      IsPrime := false;
      exit;
    end;
    d := d + 1;
  end;
end;

begin
  readln(n);
  for i := 2 to n do
    if IsPrime(i) then
      write(i, ' ');
  writeln;
end.
Ввод
30
Вывод
2 3 5 7 11 13 17 19 23 29

Как проверить одно число и что такое решето Эратосфена — в справке Как проверить, простое ли число.

НОД и НОК

Задача. Найти наибольший общий делитель и наименьшее общее кратное двух натуральных чисел.

Алгоритм Евклида: НОД(a, b) = НОД(b, a mod b), а когда остаток станет нулём, ответ — оставшееся число. НОК находится через НОД: a · b / НОД(a, b).

Pascal
program GcdLcm;
var
  a, b, x, y, t: longint;
begin
  readln(a, b);
  x := a;
  y := b;
  while y <> 0 do
  begin
    t := x mod y;
    x := y;
    y := t;
  end;
  writeln('НОД = ', x);
  writeln('НОК = ', a div x * b);
end.
Ввод
84 36
Вывод
НОД = 12
НОК = 252

Копии x и y нужны, чтобы исходные a и b сохранились для НОК. НОК считается как a div x * b, а не a * b div x: сначала деление, и промежуточное число не выходит за предел longint раньше времени.

Факториал

Задача. Вычислить n! = 1 · 2 · … · n.

Pascal
program Factorial;
var
  n, i: integer;
  f: int64;
begin
  readln(n);
  f := 1;
  for i := 2 to n do
    f := f * i;
  writeln(n, '! = ', f);
end.
Ввод
15
Вывод
15! = 1307674368000

Факториал растёт очень быстро: в longint помещается только до 12!, в int64 — до 20!. Копилку произведения начинают с 1, а не с 0 — иначе всё произведение будет нулём.

Числа Фибоначчи

Задача. Вывести первые n чисел Фибоначчи (n ≥ 2): первые два равны 1, каждое следующее — сумма двух предыдущих.

Pascal
program Fibonacci;
var
  n, i: integer;
  a, b, c: longint;
begin
  readln(n);
  a := 1;
  b := 1;
  write(a, ' ', b);
  for i := 3 to n do
  begin
    c := a + b;
    write(' ', c);
    a := b;
    b := c;
  end;
  writeln;
end.
Ввод
10
Вывод
1 1 2 3 5 8 13 21 34 55

Хранятся только два последних числа: после вычисления c они «сдвигаются» — a становится b, b становится c.

Перевод в двоичную систему

Задача. Записать натуральное число в двоичной системе.

Остатки от деления на 2 — это двоичные цифры справа налево. Каждая новая цифра приклеивается к строке слева:

Pascal
program ToBinary;
var
  n: longint;
  s: string;
begin
  readln(n);
  if n = 0 then
    s := '0'
  else
    s := '';
  while n > 0 do
  begin
    if n mod 2 = 0 then
      s := '0' + s
    else
      s := '1' + s;
    n := n div 2;
  end;
  writeln(s);
end.
Ввод
13
Вывод
1101
n n mod 2 строка s — новая цифра слева 13 1 1 div 2 6 0 0 1 div 2 3 1 1 0 1 div 2 1 1 1 1 0 1 div 2 0 цикл закончен 8 4 2 1 веса разрядов
Число 13 делят на 2, пока оно не станет нулём: остатки 1, 0, 1, 1 по очереди приклеиваются к строке s слева, и получается 1101, где разряды весят 8, 4, 2 и 1.

Проверка: 1 · 8 + 1 · 4 + 0 · 2 + 1 · 1 = 13. Для другой системы счисления число делят на её основание, а остаток записывают цифрой этой системы; в системах с основанием больше 10 вместо остатков 10, 11, 12… пишут буквы A, B, C…

Палиндром

Задача. Проверить, читается ли строка одинаково слева направо и справа налево.

Первый символ сравнивается с последним, второй — с предпоследним и так до середины:

Pascal
program Palindrome;
var
  s: string;
  i, n: integer;
  ok: boolean;
begin
  readln(s);
  n := length(s);
  ok := true;
  for i := 1 to n div 2 do
    if s[i] <> s[n - i + 1] then
      ok := false;
  if ok then
    writeln('Палиндром')
  else
    writeln('Не палиндром');
end.
Ввод
racecar
Вывод
Палиндром

Символу s[i] в пару стоит s[n - i + 1]: для i = 1 это последний символ, для i = 2 — предпоследний.

r = r a = a c = c r 1 a 2 c 3 e 4 c 5 a 6 r 7 середина — без пары n = 7 i n - i + 1 1 ↔ 7 2 ↔ 6 3 ↔ 5 i — до n div 2 = 3
В слове racecar из 7 букв сравниваются пары символов 1 и 7, 2 и 6, 3 и 5 — в каждой буквы совпадают, а средняя, четвёртая, пары не имеет, поэтому цикл идёт до n div 2 = 3.

Как решать новые задачи

Коротко

Проверьте себя

1. Как получить последнюю цифру числа n?
2. Почему делители при проверке на простоту перебирают только пока d * d <= n?
3. Чему равен НОД чисел 84 и 36 по алгоритму Евклида?
4. Почему переменную для факториала начинают с 1, а не с 0?