Блог пользователя rustam-cpp

Автор rustam-cpp, история, 4 месяца назад, По-русски

Привет, CodeForces!

Основная информация

Я написал генератор тестов на C++. Он очень прост, состоит из двух функций: генерация случайного числа в промежутке от $$$a$$$ до $$$b$$$, так, чтобы это случайное число было кратно $$$k$$$ (функция: genint(a, b, k, add), где add — "добавлять" ли в тест это число) и генерация случайной строки. Тут надо расписать:

  • Генерирует строку случайной длины в промежутке от $$$a$$$ до $$$b$$$, так, чтобы она была кратна $$$k$$$.
  • Состоящую из заданных символов. Задавать символы можно двумя способами: написать промежуток ("a-f", "x-z") или конкретный символ ("m", "o"). Функция: genstr(a, b, k, pattern, add), где pattern — массив заданных промежутков или конкретных символов.
Код

Применения

Есть такая задача: Вам дана строка состоящая из $$$n (n \le 10^5)$$$ символов. Вам требуется процент содержания (с точностью до $$$10^{-5}$$$) каждого символа, который есть в строке. Пример ввода и вывода:

Пример

Вам требуется обработать $$$t$$$ наборов входных данных

Для нас, участников соревнования, эта задача очень проста, но для составителей надо написать такие тесты, в которых будут и крайние и обычные случаи. Писать это вручную — плохой вариант. Тем более, что $$$n \le 10^5$$$

С помощью моего генератора можно сделать хорошие тесты в несколько строк:

const int mintestcases = 5;
const int maxtestcases = 8;
const int minlength = 10;
const int maxlength = 20;
for (int i = 0; i < 5; i++) { // генерирует 5 тестов
  string test = "";
  int t = genint(mintestcases, maxtestcases, 1, true);
  test += '\n';
  for (int j = 0; j < t; j++) {
    int n = genint(minlength, maxlength, 5, true);
    test += '\n';
    genstr(n, n, 1, {"a-z"}, true);
    test += '\n';
  }
}
Тесты

Чтобы сделать большие тесты надо увеличить значения mintestcases, maxtestcases, minlength, maxlength. Для претестов можно взять по 1-2 тесту каждого "размера".

Можно генерировать строки состоящие из заглавных букв: genstr(10, 20, 5, {"A-D"}, true), результат: DCABACCCABBBDBD

Можно и сгенерировать строку состоящую из строчных и заглавных букв: genstr(10, 20, 5, {"A-D", "a-d"}, true), результат: DcaBaccCABBBDBD

Заключение

Этот генератор подойдет и для стресс тестирования. Генерировать тесты в задаче обычно не очень сложно. Подойдет он и для взломов. Можно очень легко сгенерировать "максимальный" тест.

Всем удачных раундов и высокого рейтинга, пока!

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

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

I'm having a hard time understanding the purpose of this blog. What's your target audience? Are you teaching author's how to generate testcase?

Also, You used rand() function without setting seed. Without it, every time you run it, this will generate same output. Better to set srand(time(NULL)).

Or even better, use mt19937 mt(chrono::steady_clock::now().time_since_epoch().count());. Learn more about it here.

  • »
    »
    4 месяца назад, # ^ |
      Проголосовать: нравится +3 Проголосовать: не нравится

    "Are you teaching author's how to generate testcase?" — No, I do this: "This generator is also good for stress testing. Generating tests in a task is usually not very difficult. Also it can be used for hacks. You can generate a "maximal" test very easily."

    • »
      »
      »
      4 месяца назад, # ^ |
      Rev. 2   Проголосовать: нравится +7 Проголосовать: не нравится

      I've never done hacking, but I believe whole purpose of hacking is to exploit a user's submission. It's often not random. Probably exploiting corner case, trying to get TLE, MLE, RE using deliberate testcases. And those who enjoy hacking, do know what they are doing. It's probably not useful for them either.

      But let's see, what others have to say.

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

    srand(time(NULL)) — i forget about it =)

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

    And why do you need a getint() function that generate nums in multiples of k?

    Isn't the following enough? (To generate a number in range)

    mt19937 mt(chrono::steady_clock::now().time_since_epoch().count());
    int rand(int l, int r) { return l + mt() % (r - l + 1); }
    
»
4 месяца назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Глянь https://github.com/emil-e/rapidcheck как идею для тестирования и как API