Как ускорить вычисления программы?
Здравствуйте! Есть такая задачка:
У вас есть 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 шт):
Сложить левые и правые концы интервалов ключей, в массив записей вида (номер; +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, если количество замков не было достигнуто.
Как это работает? Представьте диаграмму Гантта. Если какой-то интервал покрыт всеми полосками, то это как раз интервал номеров ключей, открывающих все замки.
Ответ на задачу очевидно получается, если найти все ключи, которые открывают все замки. Тогда медленное решение: перебрать каждый ключ и проверить, входит ли он в каждый из M отрезков.
Чтобы его ускорить, нужно заметить, что задача переформулируется следующим образом: "Найти все целые точки, принадлежащие каждому из M отрезков". Такая формулировка сразу же наталкивает на мысль о пересечении отрезков. Таким образом, ответом будет количество точек в пересечении всех отрезков.