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

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

Я составляю задачу для одной олимпиады, в апреле планируется добавить тренировку в CF по задачам той олимпиады

Допустим, есть строка A = "abc", B = "def". Мне нужно их вывести, чтобы на выходе получить "abcdef". Таких строк может быть до 4 × 106 штук.

Как можно это делать быстро в С++? На Delphi решение тратит 937 мс, на C++ — 1703 мс.

Код Delphi:

write('abc');
write('def');

Код С++:

printf("abc");
printf("def");

Да, это укладывается в установленный TL = 2 секунды. Но хотелось бы быстрее. Можно ли?

UPD: Конкатенировать строки нельзя, задача на технику, ML = 4 МБ, поэтому решение с конкатенацией получает ML.

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

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

puts не быстрее?

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

    В С++ я не силён, многого не знаю.

    Я пробовал puts, он после каждой строки выводит \n, а так не надо.

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

      Заведи большой буффер. Пихай все в него и потом один раз делай puts. Это очень быстро работает.

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

        Написано же в посте: "UPD: Конкатенировать строки нельзя, задача на технику, ML = 4 МБ, поэтому решение с конкатенацией получает ML."

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

    puts выводит '\n' после окончания строки

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

Попробуйте fputs(str,stdout)

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

Попробуйте fputs("abc", stdout); fputs("def", stdout);

Еще вариант:

void myputs(const char *s) {
  int len = strlen(s);
  fwrite(s, 1, len, stdout);
}
// ...
myputs("abc");
myputs("def");
  • »
    »
    13 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится +5 Проголосовать: не нравится

    fputs дал ускорение на 400 мс.

    myputs дал ускорение на 150 мс.

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

      Попробуй в myputs

      fwrite(s, 1, len, stdout);
      

      заменить на банальное

      for (int i = 0; i < len; ++i) putc(s[i], stdout);
      

      У меня это дало 3-кратное ускорение (не забыть сделать myputs inline — у меня ускорило до 0.204 сек для вывода 4000000 "abc" "def")

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

        Наверное, ты удивишься: с inline получило TL.

        P.S. без inline тоже.

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

          Странно. У меня такие результаты:

          putc   - 0.155000
          myputs - 0.520000
          puts   - 0.855000
          printf - 1.302000
          
          • »
            »
            »
            »
            »
            »
            13 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится

            Естественно, у меня далеко не "abc" и "def", возможно, из-за этого.

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

    fwrite() только хуже сделает, потому что это запись напрямую в буфер ядра ОС, в обход буфферизации в libc

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

Попробуй собрать все строки в одну большую строковую переменную, а потом выведи printf("%s\n", ans.c_str());

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

    Упс, забыл сказать самое главное. Прочитай UPD в посте.

»
13 лет назад, # |
Rev. 2   Проголосовать: нравится +28 Проголосовать: не нравится

Что-то не верится, что Delphi такой быстрый. 24 МБ за 0,046 сек даже теоретически не записать на диск. 24 МБ / 0,046 сек ~ 521 МБ/сек ~ 4174 МБит/сек, что на порядок больше даже SSD.

У меня результаты такие:

printf: 2.34
puts:   1.18
myputs: 1.58
putc  : 0.34
Delphi: 1.23
  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Да, я не туда посмотрел. В старом комплекте не было больших тестов.

    Delphi: 937 мс. С++ (самый быстрый результат — твой myputs): 1311 мс.

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

    Я бы добавил сюда fputs.

    putc  : 0.34
    fputs : 0.40
    

    Если я правильно понимаю, puts после себя делает fflush, а fputs не делает. Кстати, это правда? :-)

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

можно попробовать write(1,str,strlen(str)); это низкоуровневый вывод, но немогу точно сказать за сколько выполнется

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

    Смотря где, на то он и низкоуровневый :) Для меня низкоуровневый будет так:

    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), str, strlen(str), NULL, NULL);
    
»
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

и еще можно вопрос, как проверить скорость работы программы?

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

По этой теме есть ещё вот такой пост: http://codeforces.net/blog/entry/562

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

ML = 4 МБ — не лучшее решение для тренировок CF, теперь ее нельзя сдать на Java

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

    Мы делаем не тренировку на CF, а олимпиаду для младших школьников. Первые несколько задач рассчитаны только на технику программирования, поэтому содержат огромное количество всяких специальных случаев и тестов к этим случаям. А потом добавим тренировку на CF.

    Да, с Java есть такие проблемы. Но в прототипе правил уже есть пункт о том, что

    Жюри гарантирует наличие полного решения на языках программирования Pascal / Delphi и C / C++. Жюри не гарантирует наличие полных решений на других языках программирования.

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

Я бы все-таки сделал буфер мегабайта на 3, ускориться должно в разы.

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

    Я не знаю какой буфер вы имели ввиду, поэтому уточню : 1. Буфер — массив в коде программы 2. Буфер libc, через setvbuf()