Как ускорить вычисления программы?

Здравствуйте! Есть такая задачка:

У вас есть N ключей и M замков, ключи пронумерованы целыми числами от 1 до N, а замки пронумерованы целыми числами от 1 до M. Замок с номером i могут открыть все ключи с номерами от Li до Ri. Сколько ключей могут открыть все замки?

Формат ввода

В первой строке записаны два числа N, M (1 ≤ N, M ≤ 2 ⋅ 10^5). Каждая из следующих M строк содержит по два числа Li, Ri (1 ≤ Li ≤ Ri ≤ N).

Формат вывода

Выведите количество ключей, которые могут открыть все замки.

Пример 1

Ввод

4 2

1 3

2 4

Вывод

2

Пример 2

Ввод

10 3

3 6

5 7

6 9

Вывод

1

Пример 3

Ввод

100000 1

1 100000

Вывод

100000

Лимит памяти: 256 мб.

Лимит времени: 1 секунда.

У меня такой код:

uses crt;
var i, j, d: longint;
    k, v, s, f: longint;
    n, m: 1..250000;
    key1, key2: 1..250000;
    a: array [1..300000] of longint;
    r: array [1..300000] of longint;
    l: array [1..300000] of longint;
begin
read(n, m);
s:=1;

for i:=1 to m do
 begin
  read(key1, key2);
  r[i]:=key1; l[i]:=key2;
  for j:=r[i] to l[i] do
   begin
    f:=f+1;
    a[s]:=j;
    s:=s+1;
  end;
end;

if (m = 1) then writeln(l[1])
else
 begin
  while 1 <= f do
   begin
    s:=0;
    i:=1;
    v:=f;
    k:=a[1];

    while i <= v do
     begin
      if a[i] = k then
       begin
        s:=s+1;
        for j:=i to v-1 do
         a[j]:=a[j+1];
         v:=v-1
      end else i:=i+1;
    end;

    if (s mod m = 0) then d:=d+1;
    f:=f-s;
  end;

  writeln(d);
end;

end.

Минус моей задачи в том, что для больших чисел вычисления идут больше секунды, хотя надо меньше. Просьба решить так, чтобы всё вычислялось быстро. Мне надо решить эту задачу так, как бы это сделал ученик 8 класса, ну или чуть посложнее. Я попробую понять.

P.S. Это олимпиадная задача, если кто знает, то объясните почему в половине тестах выдаётся runtime-error.


Ответы (2 шт):

Автор решения: MBo

Сложить левые и правые концы интервалов ключей, в массив записей вида (номер; +1 для L/-1 для R)

type TRec = record
  X, Y: longint;
end;
A: array[400000] of TRec;

Rec: TRec;

read(key1, key2);
Rec.X := key1;
Rec.Y := 1;
A[2*i-1] := Rec;
Rec.X := key2;
Rec.Y := -1;
A[2*i] := Rec;

Отсортировать массив по первому полю. При равенстве первых полей учитывать второе (сначала запись с +1).

Счётчик = 0

Пройти по массиву, добавляя к счётчику второе поле.

Когда счётчик станет равным количеству замков - запомнить позицию A

Когда счётчик уменьшится с этого уровня - позиция B

Нужный результат - B-A+1 или 0, если количество замков не было достигнуто.

Как это работает? Представьте диаграмму Гантта. Если какой-то интервал покрыт всеми полосками, то это как раз интервал номеров ключей, открывающих все замки.

→ Ссылка
Автор решения: EzikBro

Ответ на задачу очевидно получается, если найти все ключи, которые открывают все замки. Тогда медленное решение: перебрать каждый ключ и проверить, входит ли он в каждый из M отрезков.

Чтобы его ускорить, нужно заметить, что задача переформулируется следующим образом: "Найти все целые точки, принадлежащие каждому из M отрезков". Такая формулировка сразу же наталкивает на мысль о пересечении отрезков. Таким образом, ответом будет количество точек в пересечении всех отрезков.

→ Ссылка