В связи с появлением поддержки javascript на codeforces (что меня очень обрадовало), я решил попробовать решить на нём пару задач. Результаты этой попытки, а также этот комментарий сподвигли меня на написание этой статьи. Итак, ниже представлен краткий список наиболее острых проблем и нюансов, с которыми вам скорее всего прийдётся столкнуться, если вы хотите использовать javascript на codeforces.
1) Вывод большого объёма данных мелкими порциями
Итак, рассмотрим следующий пример кода:
for(var i=0; i<1000000; i++) print('foobar');
Его запуск через "запуск" на codeforces даёт следующий результат:
Использовано: 702 мс, 0 КБ
Рассмотрим, как можно оптимизировать вывод:
var answer = '';
for(var i=0; i<1000000; i++) answer+='foobar\n';
print(answer);
Результат:
Использовано: 140 мс, 37852 КБ
Как видим, использование буферизации ускорило код в 5 раз, засчёт уменьшения издержек на вызовы функций. Однако потребление памяти очевидным образом возросло. Но навряд ли объём вывода какой-либо программы может значительно повлиять на получение программой Memory Limit Exceed.
2) Работа с большими числами (не длинная арифметика, просто с большими)
Итак, рассмотрим, как представляются числа в javascript, а точнее, в его данной конкретной реализации, V8. В случае, если число целое, то оно хранится таким образом:
- Если это возможно, то как 31-битное целое
- float64 (C++ double) в противном случае.
Рассмотрим, к чему это приводит: пока наше число целое, всё хорошо. Но числа с плавающей точкой имеют следующую особенность: количество представимых в них целых чисел ограничено размером мантиссы. У double размер мантиссы 52 бита, то есть величина целого числа, с которым мы вприципе можем работать штатными средствами javascript, не прибегая к каким-либо ухищрениям в виде длинной арифметики, не преышает по модулю 2^52 = 4503599627370496. Поскольку в этом числе 16 цифр, мы можем сказать, что это гарантирует нам представление 15 десятичных цифр(против 19 для long long). Это приводит к невозможности решения некоторых задач (например, 374B, которую, я собственно и пытался сдать на javascript), штатными средствами.
3) Дополнительные источники информации + пара полезностей
Про оптимизацию ваших скриптов под V8 можно дополнительно почитать тут. Также, поскольку у меня не было d8
, я использовал для тестирования NodeJS. Помимо прочего, причиной этого стала более полная поддержка NodeJS в IDE и текстовых редакторах (например, WebStorm и Sublime Text соответственно). Для того, чтобы интерфейс взаимодействия оставался неизменным, и можно было спокойно копипастить код, не переделывая с нодовских process.stdout.write или console.log на readline'ы и print'ы, я написал следующий код под ноду:
process.stdin.resume();
process.stdin.setEncoding('utf8');
var input= '', readline, print;
process.stdin.on('data', function(chunk) {
input+=chunk;
});
process.stdin.on('end', function() {
input = input.split('\n');
print = function(data) {process.stdout.write(data+'\n')};
var inputLineIndex = 0;
readline = function(){return inputLineIndex>=input.length?undefined:input[inputLineIndex++]};
process.exit(main() || 0);
});
function main()
{
// Your code here
return 0;
}
Посылать в качестве решения функцию main, и не забыть добавить в конце вызов или обернуть в замыкание:
function main()
{
// Your code here
return 0;
}
main();
// или
(function main()
{
// Your code here
return 0;
})()
P.S. Рассмотрено совсем немного проблем, но это были те проблемы, с которыми я столкнулся СРАЗУ, как только попытался решать задачи на javascript. Если вы можете предложить ещё какие-либо важные "грабли", на которые легко наступить при решении на javascript многих задач, пишите в комментарии, буду рад дополнить статью новыми примерами.