Блог пользователя Kondrat_Voronov

Автор Kondrat_Voronov, 11 лет назад, По-русски

В связи с появлением поддержки 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 многих задач, пишите в комментарии, буду рад дополнить статью новыми примерами.

Полный текст и комментарии »

  • Проголосовать: нравится
  • +24
  • Проголосовать: не нравится