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

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

На предыдущем контесте (Round #177, div.2) случилось страшное, однако для меня обыденное — задача С, по которой я сделал шесть взломов у меня упала по TL. Вот код.

Я, перечитав код, начал пенять на сложение строк. Скажите, это оно виновато в моем горе, или я неправ, и ошибка в другом? Если это сложение строк, то скажите, почему оно так долго работает?

Спойлер: массив "a" не имеет применения в данном коде.

UPD: операция "+" для строк для работает за линию.

Будьте бдительны!

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

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

Тут написано "Complexity: Unspecified, but generally up to linear in the new string length."

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

    Это кошмар и ужас. Но зато теперь буду знать. Спасибо.

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

    Это сложность выполнения одной операции. Амортизированная сложность кучи сложений будет видимо близка к O(итоговая длина).

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

      s = (char)('a' + i) + s;

      Вот здесь это точно будет квадрат.

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

    Это относится к тем же приколам, что бывают с векторами. То есть в случае, когда нужно сделать реаллокацию, сложность действительно будет O(new_length). В остальных случаях O(1). То есть амортизированная сложность в итоге будет O(length).

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

И действительно:

for (int i = k - 1; i > 1; --i)
    s = (char)('a' + i) + s;
for (int i = 0; i <= n; ++i)
    s1 = s1 + (char)('a' + (i % 2));

В случае строк посмотрим на оператор +:

template<typename _CharT, typename _Traits, typename _Alloc>
  basic_string<_CharT, _Traits, _Alloc>
  operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
            const basic_string<_CharT, _Traits, _Alloc>& __rhs)
  {
    basic_string<_CharT, _Traits, _Alloc> __str(__lhs);
    __str.append(__rhs);
    return __str;
  }

И на оператор +=:

basic_string&
operator+=(const basic_string& __str)
  { return this->append(__str); }

То есть ваш код работал за квадрат, так как создавался объект на основе первой строки, затем уже к нему добавлялась вторая строка. В случае строк лучше делать +=. Так как не создаются объекты, если они нам не нужны, а работает, как push_back в массиве.

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

Странно пенять на операцию "+=", которой в вашем коде вообще нет. Эта операция работает быстро. У вас же каждый раз выполняется простое присваиваение s = s+один_символ. Это, конечно, работает долго.

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

Всю жизнь строки складывал так же, как ты. Спасибо за подсказку, больше так делать не буду :3

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

Понятно же, что s = t + s будет работать за квадрат. Нельзя просто так взять и дописать элементы спереди. Если уж очень надо, то deque<char> какой-нибудь поможет, наверно.

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

    Ну такого там нет. Там все-таки s = s + t, но только суть от этого не меняется. Не знаю, как в джаве, но в плюсах точно происходит создание того, что я описал выше. В принципе могу выложить сюда и код того, как работает append, но это вряд-ли целесообразно, у всех он и так есть :)

    UPD. s = t + s там тоже есть, но таких операций не более, чем k. То есть мало.

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

      В джаве строка — неизменяемый объект, поэтому там всегда при сложении создаётся новый объект.