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

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

Товарищи, в процессе подготовки одной задачки я обнаружил странное поведение следующей программы на серверах Codeforces.

import java.io.*;
import java.math.BigInteger;
import java.util.*;

public class Primorial {

    public static void main(String[] args) throws Exception {
        int n = Integer.parseInt(new BufferedReader(new InputStreamReader(System.in)).readLine());
        BigInteger primorial = BigInteger.ONE;
        BigInteger prime = BigInteger.ONE;
        for (int i = 1; i < n; ++i) {
            prime = prime.nextProbablePrime();
            primorial = primorial.multiply(prime);
        }
        System.out.println(primorial);
    }

}

Для n = 5 этот код выполняется примерно за 30 миллисекунд, а для n = 6 уже примерно за 5 секунд. Это верно как для шестой джавы, так и для седьмой. Проверял как на полигоне, так и в форме запуска на Codeforces. Результат печальный.

2310
=====
Использовано: 5038 мс, 1080 КБ

То есть целых 5 секунд тратится на понимание того, что следующее за семёркой простое число — 11. Между тем у меня на локальном компьютере, а также в других местах такая программа работает быстро.

Единственное объяснение, которое я могу предложить, — что это как-то связано с использованием java.security.SecureRandom. Но нормально ли это, как по-вашему? Ведь метод довольно хитрый и участники могут воспользоваться им во время раундов. Должен ли он себя так вести?

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

»
11 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Я думаю, что ненормально захардкоженое использование SecureRandom в nextProbablePrime. На это участники уже натыкались (например, cerealguy на финале RCC получал из-за этого RT/1, потому что не было прав на запись всяких параметров для SecureRandom).

Мне кажется, правильным решением было бы одно из двух:

  1. Разрешить сбор параметров, необходимых SecureRandom. Вряд ли они содержат что-то критичное. Но не удивлюсь, если можно их разрешить только вместе с чем-нибудь важным (скажем, доступу к сети).
  2. Руками подменить класс SecureRandom на что-нибудь быстрое на всех judge-машинах. Это выглядит костыльно, однако надёжно в данном конкретном случае и не будет проблем с правами.
  • »
    »
    11 лет назад, # ^ |
      Проголосовать: нравится +15 Проголосовать: не нравится

    Ага, на Тимусе была такая же проблема. Пошли по второму пути: http://acm.timus.ru/forum/thread.aspx?id=28369

  • »
    »
    11 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    По поводу 1 — почему бы не разрешить вообще всё, и подсунуть фейковое окрушение? Хочет программа сеть — пусть пользуется фейковой сетью сколько хочет. Запуск в реальном окружении с ограничениями всё равно даёт только видимость безопасности (exploit'ы никто не отменял), так что фейковое окружение (виртуалки, light-виртуализация с помощью cgroups, etc.) — ИМХО правильный подход.

    • »
      »
      »
      11 лет назад, # ^ |
      Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

      Любые виртуалки (VirtualBox, QEMU) тормозят, что не очень хорошо. Особенно ввод-вывод. А вот с cgroups, думаю, есть некоторая проблема — тестирование под Windows. И потом, кто отменял exploit'ы в cgroups?

      UPD: разумеется, фейковое окружение лучше. Но в Windows его вообще не добиться цензурными методами. Например, сеть вообще никак не ограничивается (кроме firewall'ов, которые делают что-то хитрое), насколько я знаю. Аналогов chroot и прочего также нет.

      Зато есть вижуалка, поддержку которой хочется иметь.

      • »
        »
        »
        »
        11 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        Да, с виндой проблема, и её самостоятельно допилить не получится, даже если есть желание :( А компилятор от Visual Studio не работает с wine? Или там тормоза? Если тормозов нет — cgroups + wine было бы отличным решением.

»
11 лет назад, # |
  Проголосовать: нравится +25 Проголосовать: не нравится

Открыл эту страницу и аж вздрогнул.

»
11 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Читаем здесь

»
11 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

В качестве workaround'а — а нельзя похакать BigInteger, чтобы он обычный рандом использовал? Кажется, здесь что-то похожее делают, надо будет попробовать.