The Curse 0 / 0 / 0 Регистрация: 08.10.2018 Сообщений: 5 |
||||
1 |
||||
12.11.2018, 13:57. Показов 2912. Ответов 5 Метки acmp, начинающему, олимпиада, ошибка компиляции (Все метки)
Вот код
__________________
0 |
261 / 111 / 53 Регистрация: 22.01.2017 Сообщений: 448 |
|
12.11.2018, 14:07 |
2 |
The Curse, в скобки long long во время привидения типа, для начала.
1 |
0 / 0 / 0 Регистрация: 08.10.2018 Сообщений: 5 |
|
12.11.2018, 14:38 [ТС] |
3 |
n1b1ru, похоже у них компилятор не знает min и algorithm
0 |
261 / 111 / 53 Регистрация: 22.01.2017 Сообщений: 448 |
|
12.11.2018, 15:34 |
4 |
The Curse, может быть. А на long long реагировал? С++11 все-таки
0 |
TRam_ зомбяк 1564 / 1213 / 345 Регистрация: 14.05.2017 Сообщений: 3,936 |
||||||||||||
12.11.2018, 15:45 |
5 |
|||||||||||
Сообщение было отмечено The Curse как решение Решениеstd::min есть только начиная с C++14 А так используй if else или оператор «?» . А ещё лучше — использовать массив вместо С, H, O + цикл. Добавлено через 1 минуту
Добавлено через 1 минуту
если сделать просто
всё будет работать точно так же.
1 |
261 / 111 / 53 Регистрация: 22.01.2017 Сообщений: 448 |
|
12.11.2018, 17:14 |
6 |
std::min есть только начиная с C++14 Некоторые реализации. В 98 было обычное сравнение (ваш пример функции), а так же с предикатом
0 |
Содержание
- 1 Общий принцип
- 2 Ввод и вывод данных
- 3 Тестирование решений
- 3.1 CE — Ошибка компиляции (Compilation Error)
- 3.2 TLE — Нарушен предел времени (Time Limit Exceeded)
- 3.3 ILE — Нарушен предел ожидания (Idleness Limit Exceeded)
- 3.4 MLE — Нарушен предел памяти (Memory Limit Exceeded)
- 3.5 RTE — Ошибка во время выполнения (Run-time Error)
- 3.6 PE — Ошибка представления (Presentation Error)
- 3.7 WA — Неправильный ответ (Wrong Answer)
- 3.8 OK — Принято (Accepted)
- 3.9 CF — Ошибка тестирования (Check Failed)
- 3.10 SV — Нарушение безопасности (Security Violation)
- 4 Особенности языков программирования
- 4.1 Выбор языка программирования
- 5 Конфигурация тестирующего сервера
- 6 Языки программирования
Общий принцип
В систему посылаются только файлы с исходным кодом, а сама посылаемая программа должна состоять только из одного файла: *.dpr
, *.cpp
, *.java
, *.pas
и т. д. Нельзя отправить в систему скомпилированный exe-файл, файл проекта Visual Studio и т. п.
В решениях запрещается:
- осуществлять доступ к сети;
- выполнять любые операции ввода/вывода, кроме открывания, закрывания, чтения и записи стандартных потоков stdin, stdout, stderr и файлов с именами, явно прописанными в условии задачи;
- сознательно «ломать» тестирующую систему;
- выполнять другие программы и порождать новые процессы;
- изменять права доступа к файловой системе;
- работать с поддиректориями;
- создавать и манипулировать ресурсами GUI (окна, диалоговые сообщения и т. д.);
- работать со внешними устройствами (звук, принтер и т. д.);
- выполнять прочие действия, призванные нарушить ход учебного процесса.
Решения выполняются в специальном окружении, обеспечивающем безопасный запуск, и попытка выполнить какие-либо из указанных действий закончится, скорее всего, получением вердикта «Ошибка во время выполнения».
Ввод и вывод данных
Во всех задачах необходимо считывать входные данные из текстового файла и выводить результат в текстовый файл. Имена файлов указаны в условии задачи. Предполагается, что файлы располагаются в текущем каталоге программы, поэтому в решениях можно и нужно использовать только их имена без абсолютных путей в файловой системе тестирующего сервера.
Можно считать, что изначально при запуске решения выходной файл будет отсутствовать, и решение должно его создать и записать туда ответ.
Внимательно проверяйте имена файлов в решениях на соответствие условию задачи.
Если в коде решения имена файлов указаны неверно, это может приводить к непредсказуемым последствиям. Так, если имя выходного файла указано неверно и требуемый по условию файл не создаётся, система, скорее всего, выдаст вердикт «Ошибка представления».
В случае, когда в решении на Java перепутано имя входного файла и делается попытка открыть несуществующий файл, выбрасывается исключение. Если автор решения не перехватывает его, программа завершается с вердиктом «Ошибка во время выполнения». Если же исключение обрабатывается, то вполне возможны и другие вердикты в зависимости от того, отработает ли программа и что окажется в выходном файле. Если в решении на C++ неправильно указан входной файл и ошибки специально не обрабатываются, чтение из файла может приводить к чтению произвольных данных («мусора»). Если в программе вместо чтения из файла делается попытка считать данные со стандартного ввода (stdin, который обычно связан с клавиатурой консоли), программа заблокируется («повиснет») в ожидании ввода и будет завершена с вердиктом «Превышен предел времени».
Решение может выводить произвольные данные «в консоль», то есть в стандартные потоки stdout, stderr, которые обычно связаны с консольным окном (например для отладки). Это не запрещается и не влияет на результат. Проверяется только содержимое выходного файла. Следует помнить, что на вывод тратится дополнительное время, поэтому большой объём отладочной информации может критически замедлить вашу программу. Вывод в stderr медленнее, чем в stdout, поскольку не буферизируется.
Тестирование решений
Каждое отправленное решение проходит на сервере проверку на нескольких тестах. Задача считается решённой только в случае прохождения всех тестов. Решение запускается на всех тестах, которые есть по задаче, и процесс тестирования не прерывается на первом непройденном тесте, как это делается в соревнованиях типа ACM.
Тестирование осуществляется автоматически, поэтому решения должны строго следовать формату входных и выходных данных, который описан в условии. В случае неясности можно задавать вопросы преподавателям. Если не сказано явно, все входные данные можно считать корректными и удовлетворяющими ограничениям из условия. Например, если сказано, что на входе целое число от 1 до 100 включительно, то можно считать, что это так и есть, и проверять неравенства и выводить ошибку в случае, если это не так, в коде решения нет необходимости.
Тесты по каждой задаче не упорядочены по сложности, по размеру входных данных, по какому-то иному критерию, а следуют в исторически сложившемся порядке их добавления в систему.
Не гарантируется, что первый тест в системе будет совпадать с тестом из условия (зачастую это не так).
Результатом проверки является итоговое сообщение системы и, возможно, в скобках номер первого теста, вызвавшего ошибку (если таковая имела место). Например, вердикт «Неправильный ответ (43)» означает, что решение успешно скомпилировалось и прошло без ошибок первые 42 теста по задаче, но на тесте под номером 43 выдало неверный ответ.
Далее опишем все допустимые сообщения тестирующей системы и укажем возможные причины их появления.
CE — Ошибка компиляции (Compilation Error)
Не удалось скомпилировать решение и получить исполняемый файл для запуска. Решение в таком случае, очевидно, не может быть проверено ни на одном тесте.
Посмотреть вывод компилятора и понять, почему код не удаётся скомпилировать, можно путём нажатия на иконку в таблице с вашими решениями. Наиболее частые причины ошибки компиляции: выбран неверный компилятор (для другого языка программирования или же несовместимая версия, например Java v7 вместо Java v8), отправляется не тот файл (файл проекта IDE вместо файла с исходным кодом).
Время работы компилятора ограничено 30 секундами. Если он не успел отработать по каким-либо причинам, также будет выставлен вердикт «Ошибка компиляции».
TLE — Нарушен предел времени (Time Limit Exceeded)
Для каждого теста установлено своё ограничение по времени (Time Limit) в секундах. Для разных тестов по одной задаче ограничение по времени может быть разным.
Тестирующая система учитывает так называемое процессорное время (CPU Time) выполнения процесса в операционной системе. Нет смысла делать решение задачи многопоточным, потому что распараллеливание хоть и позволяет сократить реальное время работы (Wall Time), но не уменьшает процессорное время.
Процесс-решение запускается на тесте, и если процесс не успевает завершиться в течение отведённого времени, он принудительно завершается и выставляется вердикт «Нарушен предел времени». В качестве времени работы решения на тесте указывается то время, которое процесс фактически проработал до того, как был приостановлен. Нет возможности узнать, сколько бы программа проработала, если бы не была снята по времени. Если при ограничении по времени на тест в 1 секунду вы видите, что решение получает вердикт «Нарушен предел времени» и работает 1015 мс, то нельзя это понимать как «решение чуть-чуть не успевает, надо ускорить его на 15 мс». Если решение останавливается по времени, то вывод программы никак не проверяется на предмет его правильности.
Возможные причины появления ошибки «Нарушен предел времени»:
- неэффективный алгоритм (например, в решении реализован алгоритм с временной сложностью Ω(n2), хотя задача предполагает решение за O(n log n));
- недостаточно эффективная программная реализация (идея и алгоритм правильные, но код написан не очень хорошо: например, ввод данных из файла осуществляется медленно, чрезмерно часто выделяется и освобождается память);
- попытка чтения данных с консоли (
std::cin
,scanf()
,getchar()
в C++,System.in
в Java), тогда как нужно читать входные данные из файла (в этом случае программа блокируется в ожидании ввода и зависает, не расходуя при этом CPU Time, поэтому такой случай тестирующая система обрабатывает отдельно); - ошибка в программе (например, программа входит в бесконечный цикл).
Не рекомендуется «пропихивать» медленное решение, отправляя его многократно, пока система не «согласится» его принять. Решение в любой момент может быть перетестировано и, соответственно, может перестать быть принятым из-за нарушения предела времени.
ILE — Нарушен предел ожидания (Idleness Limit Exceeded)
Программа зависла в ожидании, не потребляя при этом ресурсы процессора.
Такое может быть, например, если согласно условию чтение входных данных осуществляется из файла, а решение выполняет ввод с консоли. В этом случае процесс решения заблокируется в ожидании нажатия клавиш на клавиатуре. Через некоторое время система тестирования принудительно завершит этот процесс и выставит вердикт ILE.
MLE — Нарушен предел памяти (Memory Limit Exceeded)
Программа использует слишком много оперативной памяти, стоит проанализировать использование памяти и оптимизировать его.
Также причиной чрезмерного использования памяти может быть ошибка в программе, например, вечный цикл в теле которого на каждой или некоторых итерациях выделяется дополнительная память. К используемой памяти относится не только память с данными, но также память с кодом и программным стеком.
Ограничение по памяти есть не для всех задач. Гарантируется, что для всех тестов в рамках одной задачи ограничение по памяти одинаково.
Как и в случае нарушения ограничения по времени, программа при нарушении ограничения по памяти аварийно завершается тестирующей системой, её вывод не проверяется на правильность. Точно так же не следует воспринимать размер памяти, использованной до момента аварийного завершения, как объём, которого решению хватило бы для успешной работы. Более точно, вердикт MLE, полученный с использованием 257 МБ памяти, говорит о том, что приложение успело использовать 257 МБ памяти и было принудительно остановлено, но ничего не говорит о том, сколько памяти использовало бы приложение, не будучи принудительно остановленным.
В некоторых случаях при разовом выделении чрезмерно большого блока в памяти, этот запрос может быть не выполнен операционной системой, что в результате может привести к ошибке во время выполнения или (значительно реже) другому результату неопределённого поведения в случае с языком C++.
RTE — Ошибка во время выполнения (Run-time Error)
В операционной системе есть такое понятие, как код завершения процесса (Exit Code). Этот подход используется как в Windows, так и в ОС семейства UNIX. Это целое число, которое остаётся после прекращения выполнения программы. Общепринятое соглашение гласит, что нулевой код завершения свидетельствует о нормальном завершении процесса без ошибок, любой другой — об ошибке. Тестирующая система проверяет код завершения вашего решения, и если он не равен нулю, выставляет вердикт «Ошибка во время выполнения». При этом никак не проверяется то, что решение успело вывести в выходной файл.
Укажем типичные причины ошибок во время выполнения.
- Использована директива
package
в коде программы на Java.- В результате программа на Java находится не в пакете по умолчанию. Компилятор Java сгенерировал класс в некотором пакете (ошибки компиляции нет), а при запуске виртуальная машина Java не смогла найти этот класс, потому что искала в пакете по умолчанию (возникло исключение
ClassNotFoundException
с сообщением Could not find or load main class).
- В результате программа на Java находится не в пакете по умолчанию. Компилятор Java сгенерировал класс в некотором пакете (ошибки компиляции нет), а при запуске виртуальная машина Java не смогла найти этот класс, потому что искала в пакете по умолчанию (возникло исключение
- Выход за границы допустимой области памяти в программе на C++.
- Выход за границы массива, разыменование неправильного указателя, обращение к нулевому указателю.
- Переполнение системного стека.
- Эта причина является частой в случае рекурсии. Вообще, системный стек используется для размещения параметров функций, локальных переменных. Его размер, как правило, невелик и по умолчанию равен 1 МБ. При вызове функции стековая структура позволяет естественным образом сохранить текущие состояния всех локальных переменных и вернуться к ним, когда вызов завершится и управление вернётся в исходную точку. Если в алгоритме используется глубокая рекурсия, то размера стека может не хватить для хранения контекстов всех вызовов. Решений этой проблемы два:
- переписать алгоритм нерекурсивно (например с использованием своего стека, а не системного);
- увеличить размер системного стека, что делается по-разному для разных языков программирования (см. примеры для C++ (Visual Studio) и Java).
- Эта причина является частой в случае рекурсии. Вообще, системный стек используется для размещения параметров функций, локальных переменных. Его размер, как правило, невелик и по умолчанию равен 1 МБ. При вызове функции стековая структура позволяет естественным образом сохранить текущие состояния всех локальных переменных и вернуться к ним, когда вызов завершится и управление вернётся в исходную точку. Если в алгоритме используется глубокая рекурсия, то размера стека может не хватить для хранения контекстов всех вызовов. Решений этой проблемы два:
- Ошибка ввода-вывода (попытка открыть несуществующий входной файл).
- Нужно проверить правильность имени входного файла.
- Программа целенаправленно была завершена с ненулевым кодом выхода.
- В программе на C++ это может быть, если функция
main()
в C++ вернула ненулевой код (return (non-zero)
в функцииmain()
). Рекомендуется завершать функциюmain()
операторомreturn 0
(в старых компиляторах C++ это обязательно, современные компиляторы же подразумевают возврат нулевого кода автоматически). Также программу на C++ с произвольным кодом завершает вызовexit()
. - В программе на Java можно завершить процесс с произвольным кодом с помощью
System.exit()
.
- В программе на C++ это может быть, если функция
- Необработанное исключение.
- Причин возникновения исключений может быть масса. Например, если в Java функции
Integer.parseInt()
/Double.parseDouble()
была передана строка, содержащая пробельные символы (ASCII-коды 9, 10, 13, 32), выбрасывается исключениеNumberFormatException
.
- Причин возникновения исключений может быть масса. Например, если в Java функции
- Целочисленное деление на ноль.
- При выполнении деления нужно всегда думать, а не может ли делитель оказаться равным нулю. В то же время стоит отметить, что вещественное деление на ноль (в типах с плавающей точкой
double
,float
) по умолчанию не приводит к завершению программы, а даёт специальные значения+Inf
,-Inf
илиNaN
.
- При выполнении деления нужно всегда думать, а не может ли делитель оказаться равным нулю. В то же время стоит отметить, что вещественное деление на ноль (в типах с плавающей точкой
PE — Ошибка представления (Presentation Error)
Наиболее частая причина возникновения этой ошибки — не найден выходной файл. Возможно, вы забыли создать выходной файл и выводите ответ в консоль (он в таком случае игнорируется). Проверьте имена входного и выходного файла в вашей программе на соответствие условию задачи. Исторически сложилось, что в разных задачах входной и выходной файл именуются по разным правилам: input.txt и output.txt, in.txt и out.txt, input.in и output.out (обратите внимание, что нет расширения txt), [задача].in и [задача].out…
Для некоторых задач программа проверки (checker) дополнительно удостоверяется, что ваш вывод соответствует определённому формату, и выдаёт ошибку представления в случае, если это не так. Например, если в задаче нужно вывести число, а вы выводите строку. Или если в задаче нужно вывести сначала число k, затем k чисел, а ваше решение выводит число k и далее (k + 1) чисел (то есть решение выводит в файл лишние данные).
Также имейте в виду, что отлавливание исключений и других ошибок не должно быть самоцелью. Если исключение не обрабатывается каким-либо образом, обычно нет смысла его ловить по следующей причине. Аварийное завершение работы программы в результате ошибки во время выполнения приводит к вердикту «Ошибка во время выполнения», только если соответствующее исключение было «проброшено» наружу, а не «заглушено» на каком-то этапе. Если исключение отлавливается, но никак не обрабатывается, то в результате возникновения соответствующей ошибки следует ожидать вердикт «Ошибка представления» или же «Неправильный ответ» (реже).
WA — Неправильный ответ (Wrong Answer)
Для многих задач ответ однозначен, и проверяется просто побайтовое совпадение вашего выходного файла и сохранённого правильного ответа. Такая проверка требует строгого соблюдения формата файла, не допускает незначащих пробелов и пустых строк. Например, если правильный ответ имеет вид (пробелы обозначены символом ␣)
5 1␣2␣3␣4␣5
и решение вывело
5 1␣2␣3␣4␣5␣
(лишний пробел в конце второй строки), то будет получен вердикт «Неправильный ответ». Для некоторых задач написаны проверяющие программы (checker), которые к таким различиям лояльны и засчитывают ответы с лишними пробелами как правильные. Всегда точно следуйте формату файла и не выводите лишних пробелов, и проблем не будет.
После последней строки файла можно выводить или не выводить перевод строки — не важно. Есть две точки зрения в зависимости от того, с какой стороны смотреть на символ перевода строки:
- каждая строка завершается переводом строки, поэтому
n
в конце файла нужен; - перевод строки является разделителем между соседними строками, поэтому
n
в конце файла не нужен.
Первая точка зрения является общепринятой. Так, компилятор gcc, система контроля версий git и многие другие программы выдают предупреждение no newline at the end of file, если в самом конце файла нет символов новой строки. Обсуждение вопроса можно почитать на stackoverflow.
Поэтому рекомендуется придерживаться первого подхода и завершать все строки переводами строк.
Другие очевидные причины получения неправильного ответа:
- неверный алгоритм;
- ошибка в программе.
Бывает такое, что решение от запуска к запуску даёт разные ответы, или же правильно работает на одном компьютере и неправильно на другом. Такие случаи, как правило, связаны с ошибками в решениях.
OK — Принято (Accepted)
Программа работает правильно и прошла все тесты с соблюдением всех ограничений.
Если решение принято системой, это ещё не означает, что в его основе лежит правильный алгоритм. В любой момент могут появиться новые наборы входных данных, на которых будут заново протестированы все решения по задаче. Если ваше решение на самом деле не полностью верно и прошло только из-за недостаточно сильного набора тестов, оно может в будущем потерять статус «Принято».
CF — Ошибка тестирования (Check Failed)
Если указан номер теста, то программа успешно завершается на предложенном тесте (укладывается в отведённые время и память и не совершает ошибок во время выполнения), но результат не удаётся проверить из-за ошибок в программе проверки. Вашей ошибки в этом случае, возможно, никакой нет и после исправления программы проверки будет получен вердикт OK. Не исключены ещё два варианта: WA, PE.
Имейте в виду, что если ошибка тестирования возникает на первом же тесте, то на остальных Ваше решение не запускается вовсе. Соответственно, в этом случае после устранения ошибок программы проверки вердикты TLE, MLE, RTE также могут возникнуть в любом тесте, кроме первого.
Если же номер теста, на котором возникает ошибка тестирования, не указан, значит, программа проверки не была скомпилирована, а Ваше решение не запускалось вовсе. В этом случае правильным может быть любой вердикт, отличный от CF.
Если у Вас возникла ошибка тестирования, мы, скорее всего, это заметим достаточно быстро. Тем не менее, имеет смысл задать вопрос через пункт «Сообщения» в меню курса. Не забывайте выбрать задачу, которой касается этот вопрос.
SV — Нарушение безопасности (Security Violation)
Ошибка означает, что программа попыталась выполнить запрещённые действия.
К их числу относится попытка создания новых процессов. Вашим решениям запрещено запускать на выполнение другие программы. Например, в коде
порождается новый процесс командной оболочки cmd.exe и в нём выполняется команда pause. Пожалуйста, не пишите так, для достижения аналогичного эффекта можно использовать другие приёмы.
Особенности языков программирования
У каждого конкретного языка программирования есть свои особенности, о которых полезно знать. Далее рассмотрены отдельные особенности написания решений на разных языках программирования:
- C++;
- Java;
- C#;
- Python.
Выбор языка программирования
Разные задачи можно решать на разных языках. Часто для конкретной задачи тот или иной язык оказывается предпочтительным. Например, если в задаче требуются тяжёлые вычисления, то её может быть проще сдать на C++, чем на Java, за счёт более быстрой работы программы на C++ (для кода на Java могут потребоваться более изощрённые оптимизации, чтобы он прошёл по времени). С другой стороны, если задача требует проведения вычислений с большими целыми числами, выходящими за пределы диапазона 64-битных переменных, то есть «длинной арифметики», то решение существенно проще написать на Java, воспользовавшись готовым качественно написанным классом BigInteger
для операций с числами произвольной длины.
Конфигурация тестирующего сервера
Сервер, на котором осуществляется запуск решений, является виртуальной машиной, выполняющейся внутри Microsoft Hyper-V Server 2012 R2. Виртуальный компьютер работает под управлением Windows 7 Professional x64, оснащён процессором Intel® Core™ i3-4130 (Haswell, кэш 3 МБ, 3,40 ГГц, доступно только одно ядро) и 4 ГБ оперативной памяти. Для хранения входных и выходных файлов используется RAM-диск, чтобы обеспечить максимальную производительность ввода-вывода.
Языки программирования
На странице учебного курса в системе на вкладке «Компиляторы» можно ознакомиться с актуальным списком доступных языков программирования, версиями компиляторов и параметрами командной строки их вызова.
Размер системного стека явно не задаётся (используется размер по умолчанию). При компиляции кода на C++ включен режим оптимизации O2.
Рассмотрим процесс решения на примере задачи №274 «Дружные числа».
Логика решения достаточно проста: для каждого из проверяемых чисел опишем логический массив, в котором i-ый элемент равен 1, если число содержит цифру i. Два числа являются дружными тогда и только тогда, когда соответствующие им массивы поэлементно равны.
Ниже показаны функции для определения логических массивов и их сравнения.
void getDigits(int n, bool dn[]) { while (n) { dn[n % 10] = true; n /= 10; } } |
bool compareDigits(bool da[], bool db[]) { for (int i = 0; i < 10; i++) if (da[i] != db[i]) return false; return true; } |
Основная функция может иметь следующий вид:
int main() { int testsCnt, a, b; bool da[10], db[10]; scanf("%d", &testsCnt); for (int i = 0; i < testsCnt; i++) { scanf("%d%d", &a, &b); getDigits(a, da); getDigits(b, db); printf("%sn", compareDigits(da, db) ? "YES" : "NO"); } return 0; }
1. Отправка файла |
2. Получение вердикта проверки (CE) |
3. Просмотр сообщений компилятора |
4. Повторная попытка отправки (TLE) |
5. Третья попытка отправки (WA) |
6. Успешная попытка отправки |
7. Код корректного решения |
Когда решение составлено, его следует отправить на проверку. Для этого следует выбрать текстовый файл с кодом решения (не исполняемый файл!) в форме «Сдать задачу» и нажать кнопку «Отправить» (рис. 1). Следует иметь в виду, что система ACMP определяет компилятор, требуемый для решения, по расширению предоставленного файла (*.c и *.cpp для C/C++, *.pas и *.dpr для Pascal, *.java для Java).
После отправки решения становится доступен результат его проверки (рис. 2). В нашем случае получен вердикт «Compilation Error» (ошибка компиляции). При данном ответе системы автор может просмотреть сообщения компилятора, перейдя по ссылке с ID решения. В показанном примере (рис. 3) компилятор сигнализирует о недоступности функций scanf и printf, так как не подключен заголовочный файл <stdio.h>.
Добавим в решение строку
#include <stdio.h>
и отправим его заново (рис. 4).
Теперь система выдаёт ответ «Time Limit Exceeded» (превышен предел времени выполнения) на первом тесте. Причиной данной ошибки является то, что система ACMP предполагает файловый ввод-вывод для задач, тогда как решение использует стандартную настройку (ввод с клавиатуры, вывод на монитор); при этом программа всё отведённое время находится в состоянии ожидания ввода, а затем снимается проверяющей системой как медленно работающая.
Примеры простого перенаправления ввода-вывода для используемых в системе языков программирования приведены на странице Новичкам.Используем вариант для C++: добавим в функцию main строки
freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout);
Повторная отправка решения (рис. 5) приводит к вердикту «Wrong Answer» (неверный ответ). В большинстве задач (но не во всех) начальные тесты совпадают с тестами из условия. Трассировка решения на втором тесте позволяет выяснить причину ошибки: входные данные могут содержать несколько тестовых случаев, и перед рассмотрением каждого из них логические массивы требуется очищать.
Добавим очистку в цикл for в основной функции:
for (int j = 0; j < 10; j++) da[j] = db[j] = false;
С данной модификацией решение проходит все тесты (рис. 6, 7).
Типы соревнований: Virtual и Upsolving
В архиве соревнований вы можете заметить, что почти все сорвенования имеют два вида:
Virtual (виртуальное соревнование) и
Upsolving (дорешивание). Виртуальное сорвенование будет иметь для вас
свою обычную длительность, в нём решения других участников, уже игравших его раньше, будут появляться по мере того,
как они сдавались во время игр тех участников. После того, как виртуальное сорвенование закончилось, вы уже не сможете
сдавать туда задачи. Дорешивание — это просто бесконечно длинное соревнование, в которое можно заходить в
любое время и сдавать туда решения, которые не получилось написать на обычном или виртуальном туре.
Вердикты
Здесь находится список вердиктов, которые может получить ваше решение. Мы сообщаем номер теста,
но не сообщаем расход времени и памяти.
- WA — Wrong Answer. Ответ, выведенный вашим решением, неверен. Sad but true.
- PE — Presentation Error. Ваше решение вывело какую-то ерунду, даже отдаленно не похожую даже на неправильный ответ.
Например, если в задаче требуется вывести целое число, а вы выводите строку из маленьких латинских букв, вы получите этот вердикт. - TL — Time Limit Exceeded. Ваше решение работает слишком долго на одном из наших тестов. Проверьте, сколько операций
выполняет ваша программа, и не входит ли она в бесконечный цикл. - ML — Memory Limit Exceeded. Ваше решение потребляет слишком много памяти. Проверьте размеры ваших структур данных.
- RE — Runtime Error. Причинами этого вердикта может стать деление на ноль, выход за границу массива, переполнение
стека в результате бесконечной рекурсии и другие подобные ситуации. - CE — Compilation Error. Ваша программа не компилируется. Проверьте, правильно ли вы выбрали язык программирования
при отправке. В любом случае, при вердикте Compilation Error вам будет доступен вывод компилятора, так что вы сможете определить, что ему не понравилось в вашем идеальном коде. Это особенно касается компиляторов C++ и Pascal, т.к. вы можете пользоваться другими компиляторами (MS Visual C++ или Delphi). Штрафные попытки при ошибках компиляции не начисляются. - SV — Security Violation. Вы попытались выполнить запрещенное действие. Жюри обязательно посмотрит вашу программу и, если это была намеренная попытка дестабилизировать работу системы, вычислит вас по IP.
- OK — Accepted. Наши тесты настолько слабые, что ваше неправильное решение умудрилось на всех них дать правильный
ответ. Вы должны радоваться, потому что Accepted, полученные на контесте, не принято перетестировать.
Ввод и вывод
В системе используется стандартный консольный ввод-вывод (stdin/stdout).
Вывод в поток ошибок
Ваша программа может выводить в поток ошибок (stderr). Например, это может быть отладочная информация.
Тестирующая система игнорирует поток ошибок, так что это не может стать причиной вердиктов WA или PE.
Однако надо помнить, чтоб на вывод тратится время, поэтому, если вы будете выводить слишком много,
вы рискуете получить вердикт TL.
Допустимые символы
Пожалуйста, не используйте в своих исходниках нестандартные символы. К ним, в том числе, относятся русские буквы.
Если вы отошлете подобное решение, вам придет вердикт CE.
Переменная ONLINE_JUDGE
На сервере установлена переменная ONLINE_JUDGE. С ее помощью можно различать запуск программ на сервере и на вашем
локальном компьютере. Например, если вы предпочитаете пользоваться файловым вводом и выводом вместо стандартного,
вы можете использовать для этого переменную ONLINE_JUDGE. Чтобы подробнее показать, как это можно использовать,
приведем примеры для каждого языка программирования.
Pascal:
{$IfDef ONLINE_JUDGE} writeln('This text will be printed on the server'); {$Else} writeln('This text will be printed on your local computer'); {$EndIf}
C++:
#ifdef ONLINE_JUDGE printf("This text will be printed on the servern"); #else printf("This text will be printed on your local computern"); #endif
Java:
boolean ONLINE_JUDGE = System.getProperty("ONLINE_JUDGE") != null; if (ONLINE_JUDGE) { System.out.println("This text will be printed on the server"); } else { System.out.println("This text will be printed on your local computer"); }
C#:
#if ONLINE_JUDGE Console.WriteLine("This text will be printed on the server"); #else Console.WriteLine("This text will be printed on your local computer"); #endif
Размер стека
Вы можете не волноваться насчет размера стека: он в тестирующей системе установлен максимально возможным.
Перевод строки
Тестирующая система работает на операционной системе Linux, так что перевод строки состоит из одного символа
LF (‘n’, ASCII-код 10). В Windows переводы строки состоят из двух символов CR и LF (‘r’ и ‘n’, ASCII-коды 13 и 10).
Будьте внимательны, если это влияет на ваше решение.
Особенности компиляторов
Pascal
Версия компилятора — Free Pascal 2.6.4
Строка компиляции:
fpc -dONLINE_JUDGE -O2 -Xs -Sgic -viwn -Mdelphi -XS [src] -o [out]
Пример решения задачи A+B:
var a, b: longint; begin read(a, b); writeln(a + b); end.
C++
Версия компилятора — GNU C++ 5.3.1
Строка компиляции:
g++ -std=c++11 -Wall -O2 -DONLINE_JUDGE -fno-optimize-sibling-calls -fno-strict-aliasing -static [src] -o [out] -lm
В некоторых контестах также доступен компилятор языка C — GNU C 5.3.1. Все сказанное выше и ниже про C++ верно и для C, если это возможно. Тем не менее, если вы по какой-то причине любите решать задачи на C, мы рекомендуем вам как можно скорее прекратить это бесполезное занятие и начать писать на C++.
Стоит обратить внимание на ввод и вывод 64-битных целых чисел функциями scanf и printf.
Спецификатор «%I64d» не работает, используйте спецификатор «%lld», например:
long long x; scanf("%lld", &x); printf("%lld", x);
unsigned long long y; scanf("%ulld", &y); printf("%ulld", y);
Примеры решения задачи A+B:
- Решение с использованием C-style ввода-вывода.
- Решение с использованием потокового ввода-вывода.
#include <cstdio> int main() { int a, b; scanf("%d%d", &a, &b); printf("%dn", a + b); }
#include <iostream> using namespace std; int main() { int a, b; cin >> a >> b; cout << a + b << "n"; }
Обратите внимание, что ввод-вывод через cin / cout работает медленнее, чем через scanf / printf.
Так что если в задаче требуется считывать большие объемы данных, сразу используйте scanf / printf.
Java
Версия Java — 1.8.0_73
Строка запуска:
java -DONLINE_JUDGE -Xmx512M -Xss256M -Duser.language=en -Duser.region=US -Duser.variant=US -jar [jar]
В некоторых тестирующих системах есть ограничения на имя класса, использование вложенных классов и т.д.
У нас этого нет: вы можете использовать любое имя классов, любое количество вложенных классов.
Локаль автоматически выставлена как «en-US», так что вывод чисел с плавающей точкой через, например,
System.out.println или PrintWriter.println будет работать правильно (если по умолчанию установлена русская локаль,
вместо десятичной точки будет отображаться запятая).
Примеры решения задачи A+B:
- Короткое решение с использованием java.util.Scanner.
- Решение с использованием java.io.BufferedReader, java.util.StringTokenizer и java.io.PrintWriter.
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int a = in.nextInt(); int b = in.nextInt(); System.out.println(a + b); } }
Однако класс java.util.Scanner очень медленный, и с ним можно получить вердикт TL.
Поэтому мы приведем еще один механизм ввода-вывода, быстрый и самый популярный.
import java.io.*; import java.util.*; public class Main { private static BufferedReader in; private static StringTokenizer tok; private static PrintWriter out; private static String readToken() throws IOException { while (tok == null || !tok.hasMoreTokens()) { tok = new StringTokenizer(in.readLine()); } return tok.nextToken(); } private static int readInt() throws IOException { return Integer.parseInt(readToken()); } public static void main(String[] args) throws IOException { in = new BufferedReader(new InputStreamReader(System.in)); out = new PrintWriter(System.out); int a = readInt(); int b = readInt(); out.println(a + b); in.close(); out.close(); } }
C#
Версия компилятора — Mono C# 4.2.1.0
Строка компиляции:
gmcs -define:ONLINE_JUDGE -optimize+ [src] -out:[out]
Пример решения задачи A+B:
using System; public class Solution { public static void Main() { string[] tokens = Console.ReadLine().Split(' '); int a = int.Parse(tokens[0]); int b = int.Parse(tokens[1]); Console.WriteLine(a + b); } }
Стоит учитывать, что ввод и вывод с использованием Console.ReadLine() и Console.WriteLine() может быть медленный, и в некоторых случаях надо писать собственную реализацию. Также, один из способов ускорить вывод — добавлять выходные данные в StringBuilder, а потом один раз вывести этот StringBuilder.
Типы данных
Просматривая решения некоторых участников, жюри убедилось в том, что не все знают, что, оказывается, существуют типы данных для 64-битных целых чисел. Поэтому мы решили опубликовать список всех числовых типов данных.
Pascal
Знаковые типы
Тип данных | Размер | Диапазон значений |
shortint |
1 байт | [-128 … 127] |
smallint |
2 байта | [-32768 … 32767] |
longint |
4 байта | [-2147483648 … 2147483647] |
int64 |
8 байт | [-9223372036854775808 … 9223372036854775807] |
Беззнаковые типы
Тип данных | Размер | Диапазон значений |
byte |
1 байт | [0 … 255] |
word |
2 байта | [0 … 65535] |
longword |
4 байта | [0 … 4294967295] |
qword |
8 байт | [0 … 18446744073709551615] |
Вещественные типы
Тип данных | Размер | Диапазон значений | Точность |
single |
4 байта | [1.5E-45 … 3.4E38] |
7-8 знаков |
double |
8 байт | [5.0E-324 … 1.7E308] |
15-16 знаков |
extended |
10 байт | [1.9E-4932 … 1.1E4932] |
19-20 знаков |
C++
Знаковые типы
Тип данных | Размер | Диапазон значений |
char |
1 байт | [-128 … 127] |
short |
2 байта | [-32768 … 32767] |
int |
4 байта | [-2147483648 … 2147483647] |
long long |
8 байт | [-9223372036854775808 … 9223372036854775807] |
Беззнаковые типы
Тип данных | Размер | Диапазон значений |
unsigned char |
1 байт | [0 … 255] |
unsigned short |
2 байта | [0 … 65535] |
unsigned int |
4 байта | [0 … 4294967295] |
unsigned long long |
8 байт | [0 … 18446744073709551615] |
Вещественные типы
Тип данных | Размер | Диапазон значений | Точность |
float |
4 байта | [1.5E-45 … 3.4E38] |
7-8 знаков |
double |
8 байт | [5.0E-324 … 1.7E308] |
15-16 знаков |
long double |
12 байт | [1.9E-4932 … 1.1E4932] |
19-20 знаков |
Java
Тип данных | Размер | Диапазон значений |
byte |
1 байт | [-128 … 127] |
short |
2 байта | [-32768 … 32767] |
int |
4 байта | [-2147483648 … 2147483647] |
long |
8 байт | [-9223372036854775808 … 9223372036854775807] |
Беззнаковых типов в Java нет.
Вещественные типы
Тип данных | Размер | Диапазон значений | Точность |
float |
4 байта | [1.5E-45 … 3.4E38] |
7-8 знаков |
double |
8 байт | [5.0E-324 … 1.7E308] |
15-16 знаков |
C#
Знаковые типы
Тип данных | Размер | Диапазон значений |
sbyte |
1 байт | [-128 … 127] |
short |
2 байта | [-32768 … 32767] |
int |
4 байта | [-2147483648 … 2147483647] |
long |
8 байт | [-9223372036854775808 … 9223372036854775807] |
Беззнаковые типы
Тип данных | Размер | Диапазон значений |
byte |
1 байт | [0 … 255] |
ushort |
2 байта | [0 … 65535] |
uint |
4 байта | [0 … 4294967295] |
ulong |
8 байт | [0 … 18446744073709551615] |
Вещественные типы
Тип данных | Размер | Диапазон значений | Точность |
float |
4 байта | [1.5E-45 … 3.4E38] |
7-8 знаков |
double |
8 байт | [5.0E-324 … 1.7E308] |
15-16 знаков |
Время на сервере: 09.02.2023 13:09:34 |
Самарский государственный аэрокосмический университет © 2012 — 2023 |
#include <fstream>
#include <string>
using namespace std;
int main()
{
string s; // принятое сообщение
string n; // количество следующих сообщений
string m; // следующие сообщения
int min; // мин. кол-во отличных позиций
int k; // кол-во сообщений, которые отличаются от s мин. кол-вом позиций
string index; // их номера
ifstream fin;
fin.open("INPUT.TXT");
getline(fin, s); // считываем принятое сообщение
getline(fin, n); // считываем n
min = s.length(); // min присваиваем длину строки
for (int i = 1; fin.peek() != EOF; i++)
{
getline(fin, m); // считываем сообщение
int diff = 0; // количество отличий = 0
for (int j = 0; j < s.length(); j++)
{
if (s[j] != m[j]) // если отличаются
diff++; // то увеличиваем счетчик
if (diff > min) break;
}
if (diff < min) // если эта строка отличается на меньшее кол-во позиций
{
min = diff; // min присваиваем это кол-во отличных позиций
k = 1; // k присваиваем 1
index = "";
index = to_string(i); // вносим номер в массив
}
else if (diff == min) // если нашлось такое же кол-во позиций
{
k++; // увеличиваем k
index = index + " " + to_string(i); // вносим номер в массив
}
m = "";
}
fin.close();
ofstream fout;
fout.open("OUTPUT.TXT");
fout << k << endl << index; // выводим результат
fout.close();
return 0;
}
Задача: https://acmp.ru/index.asp?main=task&id_task=65&ins=1#solution
Harry
210k15 золотых знаков115 серебряных знаков224 бронзовых знака
задан 31 мар 2019 в 18:35
4
Если вы нажмете ссылку «обсуждение» на странице задачи, то увидите в первом же комментарии, что возможен набор входных данных с n = 0
и таковой якобы даже присутствует среди тестов. Условие задачи действительно не гарантирует положительности n
. Ваша программа, очевидно, будет выводить «мусор» для такого случая, ибо вы не инициализируете значение k
(http://coliru.stacked-crooked.com/a/bcdb82b515a1f084)
Аналогичная проблема вылезет если все сообщения m
будут отличаться от сообщения s
во всех позициях. Так как вы изначально делаете min = s.length()
, ветка if (diff < min)
не выполнится никогда, и переменной k
никогда не будет присвоено осмысленное значение (http://coliru.stacked-crooked.com/a/07ace0077df19ec9)
Другие косяки/странности в вашем коде есть, но в лабораторных условиях они мешать не должны.
ответ дан 31 мар 2019 в 19:25
Лень копаться в вашей программе на ночь глядя. Держите готовое решение…
#include <vector>
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;
size_t diff(const string& a, const string& b, size_t l)
{
size_t d = 0;
for(size_t i = 0; i < l; ++i)
d += (a[i] != b[i]);
return d;
}
int main()
{
string s;
size_t n, l, m;
cin >> s >> n;
l = m = s.length();
vector<int> v;
for(int i = 0; i < n; ++i)
{
string t;
cin >> t;
size_t d = diff(s,t,l);
if (d > m) continue;
if (d < m)
{
m = d;
v.clear();
}
v.push_back(i+1);
}
cout << v.size() << endl;
for(int i: v) cout << i << endl;
}
ответ дан 31 мар 2019 в 18:49
HarryHarry
210k15 золотых знаков115 серебряных знаков224 бронзовых знака
7