Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 30.10.2012, 22:17   #1
Ghost3
Ученик в c++
Форумчанин
 
Аватар для Ghost3
 
Регистрация: 28.02.2011
Сообщений: 162
По умолчанию Задача "Лампочки" на Pascal (№337 с acmp.ru)

Здравствуйте! Вот решил взяться за сложную задачку "Лампочки", и у меня неплохо получилось к моему удивлению
Моя программа, которую я писал минут 20, не проходит тест №6 с ошибкой Runtime error.
Есть кто решал эту задачу? Можете подсказать хотя бы примерно, что в этом 6-ом тесте?

Вот моя программа:
Код:
var n,k,i,j,x,y:longint; a,b:array[0..10000] of int64;
begin

assign (input, 'input.txt'); reset(input);
assign (output, 'output.txt'); rewrite(output);

{Присваиваю всем значениям массива 0}
read(n,k);
for i:=0 to n do
 begin
 a[i]:=0;
 end;

{считываю числа 2й строки}
for j:=1 to k do
 begin
 read(x);
 b[j]:=x;
 end;

{тут заменяю b[j]-ый элемент нулем, если он был равен единице и наоборот. b[j] - это числа со 2й строки}
for i:=0 to n-1 do
begin
 for j:=1 to k do
  begin
   if (i=0) then
   begin
   if a[i+b[j]]=1 then a[i+b[j]]:=0 else a[i+b[j]]:=1;
   end
   else
   begin
   if ((i mod b[j])=0) then
    begin
    if a[i+b[j]]=1 then a[i+b[j]]:=0 else a[i+b[j]]:=1;
    end;
   end;
  end;
end;

{здесь считаю кол-во элементов равных 1-му}
y:=0;
for i:=1 to n do
begin
if a[i]=1 then y:=y+1;
end;
writeln(y);
end.
Ps: по-моему не такая уж и супер-сложная задача, надо лишь помозговать над ней побольше.

Последний раз редактировалось Ghost3; 30.10.2012 в 22:20.
Ghost3 вне форума Ответить с цитированием
Старый 30.10.2012, 23:38   #2
Abstraction
Старожил
 
Аватар для Abstraction
 
Регистрация: 25.10.2011
Сообщений: 3,178
По умолчанию

Йолки. Пусть N=10^9. И вот Вы, такой красивый, обращаетесь в первом же цикле к a[10000], a[20000], a[20001]... дальше объяснять?
Abstraction вне форума Ответить с цитированием
Старый 31.10.2012, 11:24   #3
Ghost3
Ученик в c++
Форумчанин
 
Аватар для Ghost3
 
Регистрация: 28.02.2011
Сообщений: 162
По умолчанию

Угу, только как записать-то?
Код:
a,b:array[0..10000000000] of int64;
Ошибка: слишком большой диапозон =\

Хотя можно как-нибудь умудрится разбить a на несколько массивов...
Ghost3 вне форума Ответить с цитированием
Старый 31.10.2012, 11:29   #4
Abstraction
Старожил
 
Аватар для Abstraction
 
Регистрация: 25.10.2011
Сообщений: 3,178
По умолчанию

Правильный ответ: не надо хранить состояния всех лампочек.
Алгоритм O(N) по времени и O(P) по памяти пишется достаточно легко, но что-то мне подсказывает, что он не пройдёт по времени. А вот быстрее чем O(N) - это надо очень сильно думать, задачу простой никак не назовёшь.
Abstraction вне форума Ответить с цитированием
Старый 31.10.2012, 11:35   #5
Luuzuk
Форумчанин
 
Аватар для Luuzuk
 
Регистрация: 18.01.2012
Сообщений: 975
По умолчанию

Заменить массив списком например) Только тогда есть риск попасть на OutOfAMemory)

Попробуйте подойти к задаче несколько иначе: не писать в массив состояния всех лампочек, а только номера загоревшихся.

Псевдокод:
Код:
// у нас есть список номеров лампочек, которые горят ("А"). Он сейчас пуст

1. Считать период инверсии
2. Рассчитать номера инвертируемых лампочек (обозначим как "B")
3. Пройдем циклом по всем номерам из списка "B" ("Bi"):
  3.1. Если в списке "А" есть элемент "Bi", то удаляем его (т.к. погаснет)
  3.2. Если в списке "А" не оказалось "Bi", то добавляем "Bi" в список "А" (т.к. загорится)
4. Идем к п.1, считываем новый номер и так пока номера не кончатся
P.S. путь неоптимальный, приведен просто как пример)
Благодарить в репутацию. Проклинать — туда же
Luuzuk вне форума Ответить с цитированием
Старый 31.10.2012, 11:36   #6
Ghost3
Ученик в c++
Форумчанин
 
Аватар для Ghost3
 
Регистрация: 28.02.2011
Сообщений: 162
По умолчанию

Там время 2 секунды, неужели не хватит?

Luuzuk
Спасибо, я такой недогадливый =) Сейчас попробую.

Последний раз редактировалось Ghost3; 31.10.2012 в 11:39.
Ghost3 вне форума Ответить с цитированием
Старый 31.10.2012, 11:40   #7
Luuzuk
Форумчанин
 
Аватар для Luuzuk
 
Регистрация: 18.01.2012
Сообщений: 975
По умолчанию

Цитата:
Сообщение от Ghost3 Посмотреть сообщение
Там время 2 секунды, неужели не хватит?
При N = 10^9 на мой псевдокод времени скорее всего не хватит, как может не хватить и памяти) но выводить формулу тупо лень
Благодарить в репутацию. Проклинать — туда же
Luuzuk вне форума Ответить с цитированием
Старый 31.10.2012, 11:45   #8
Ghost3
Ученик в c++
Форумчанин
 
Аватар для Ghost3
 
Регистрация: 28.02.2011
Сообщений: 162
По умолчанию

А по-моему ваш пример куда в разы быстрее моего. И мой пока успешно проходил 5 тестов, и на 6-ом была ошибка связанная не с нехваткой времени =)

Можете подсказать как сделать цикл с шагом в "x"?

Последний раз редактировалось Ghost3; 31.10.2012 в 11:49.
Ghost3 вне форума Ответить с цитированием
Старый 31.10.2012, 11:50   #9
Abstraction
Старожил
 
Аватар для Abstraction
 
Регистрация: 25.10.2011
Сообщений: 3,178
По умолчанию

Цитата:
Сообщение от Luuzuk Посмотреть сообщение
Заменить массив списком например) Только тогда есть риск попасть на OutOfAMemory)

Попробуйте подойти к задаче несколько иначе: не писать в массив состояния всех лампочек, а только номера загоревшихся.

Псевдокод:
Код:
// у нас есть список номеров лампочек, которые горят ("А"). Он сейчас пуст

1. Считать период инверсии
2. Рассчитать номера инвертируемых лампочек (обозначим как "B")
3. Пройдем циклом по всем номерам из списка "B" ("Bi"):
  3.1. Если в списке "А" есть элемент "Bi", то удаляем его (т.к. погаснет)
  3.2. Если в списке "А" не оказалось "Bi", то добавляем "Bi" в список "А" (т.к. загорится)
4. Идем к п.1, считываем новый номер и так пока номера не кончатся
P.S. путь неоптимальный, приведен просто как пример)
Хинт: можно хранить только переключения (не более 50 элементов), после чего пройти циклом от 1 до N и для каждого значения сообразить, горит лампочка после всех переключений, или нет.
Код:
1. Прочитать в массив все инверсии (две инверсии с одним периодом отменяют друг друга) - массив из P элементов, каждый элемент - 0 или 1.
2. Переписать в другой массив (P2) те индексы, для которых элемент в P равен 1.
3. Пройти циклом от 1 до N, для каждого числа пройти по всем элементам P2 и проверить, делится или нет. Если число элементов P2, на которые делится, нечётно - добавить 1 к числу горящих лампочек.
Но, повторюсь, пройти не должно - 10^9 итераций, на каждой не менее 10 операций, даже при 4GHz это ~2.5 секунды.
Abstraction вне форума Ответить с цитированием
Старый 31.10.2012, 11:53   #10
Abstraction
Старожил
 
Аватар для Abstraction
 
Регистрация: 25.10.2011
Сообщений: 3,178
По умолчанию

Цитата:
Сообщение от Luuzuk Посмотреть сообщение
При N = 10^9 на мой псевдокод времени скорее всего не хватит, как может не хватить и памяти) но выводить формулу тупо лень
Формулу, горит ли n-ная лампочка? В общем случае вычислимой за малое время формулы не существует Нужно как-то организовывать имеющиеся делители в решётки, считать НОК каких-то подмножеств (вероятно, отделяя простые делители большие 7)... В общем, задача местами интересная, действительно.
Abstraction вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Олимпиадная задача "Золото племени АББА" на Pascal (№7 с acmp.ru) Ghost3 Помощь студентам 19 17.01.2013 21:04
Pascal ABC строки - программа, которая каждую встреченную букву "б" заменяет сочетанием "ку" (использовать модули) Raigo Помощь студентам 6 17.05.2012 15:35
написать программу по управлению клавиатурой: при нажатии "+" загораются лампочки... NickolayNest Помощь студентам 0 25.10.2011 20:07
Object Pascal "процедуры и функции" еще задача наташка-ромашка Помощь студентам 3 10.02.2011 21:25
Задача "Счастливый билет" (Turbo Pascal) - трубуется помощь BzDoN Помощь студентам 16 20.12.2009 19:29