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

Автор misha_hkl, 14 лет назад, По-русски
Предлагаю здесь выкладывать разные способы, благодоря которым можно выступить на олимпе лучше. Такие вещи на которые многие не обращают внимания. Например: если нужно искать в монотонной функции, то лучше использовать бин. поиск, а не линейный. Короче выкладывайте, то что знаете и чем не жалко поделиться.
  • Проголосовать: нравится
  • +4
  • Проголосовать: не нравится

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

1. Никогда не делайте тернарный поиск по дискретной функции.

2. Когда пишете геомерические задаче, не скупитесь на функции типа

double dist(const point& a, const point& b);

double dist2(const point& a, const point& b); //квадрат расстояния

double makeLine(const point& a, const point& b, double& A, double& B, double& C); //Создает уравнение прямой A*x + B*y + C = 0, проходящей через точки а и b.

void norm(point& a, double newLength) или

point norm(const point& a, double newLength) //Нормирует вектор по данной длинне.

Наличие функция позволяет избегать копи-пасты и структурирует код так, что в нем удобнее искать ошибки. Это особенно полезно в геометрии, так как лично у меня самые часты баги в этой теме - это тупые опечатки X вместо Y, или что-нибудь вроде

point v;

v.y /= getLength(v); v.x /= getLength(v); ))

  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    1. Почему?
    • 14 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Прошу прощения, если ошибаюсь, но как тогда разрешить такую ситуацию?

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

        P.S.

        Рисовать touch-pad'ом в Paint'е - еще то занятие.

      • 14 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Я, конечно, имел ввиду когда у нас есть строго монотонная на каждой из половинок функция. Собственно, иначе тернарный поиск не работает и для не дискретных значений - если у нас значение для среднего лефта и среднего райта равны, нам никак не выбрать, куда идти
        • 14 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится

          Да, что-то я не то нарисовал.

          Я имел в виду проблему, если мы тернаркой ищем максимум в массиве вида

          1 2 3 4 5 4 3 2 1.

          Ну вот. Осознал в чем я ошибся, когда писал сообщение.

          В этом случае нам же все равно что отсекать.  

        • 14 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          В одной задаче я учил тернарку определять, лефт это или райт. После чего она заработала. Так что можно, если умеешь определять сторону
14 лет назад, # |
  Проголосовать: нравится +1 Проголосовать: не нравится
Вообще, это хорошая идея для темы. Пора создавать базу знаний CodeForces. Что-нибудь типа википедии.
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
3. Старайтесь не заводить массивы впритык. Для размеров статических массивов лучше выбирать значение на 5-1000 превышающее максимально требуемое. Часто спасает.
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    А еще лучше заводите массивы размера n. Для плюсов - вектора. Очень многие ошибки так ловятся
    • 14 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Вектора тормозят. Иногда из-за этого не проходят решения
      • 14 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Можно пример задачи, где решение с массивами проходит а с векторами - нет?
      • 14 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Тормозит создание и доступ к элементам? Уж не тормознее чем массивы в Java на которой я пишу new int[n].
      • 14 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Решения не походят не из-за векторов, а из-за неправильного их использования. Если вы делаете много миллионов push_back'ов вместо того, чтобы сразу инициализировать вектор нужной длины, то не стоит удивляться тормозам. А доступ к элементам у векторов работает с той же скоростью, что и у массивов.
        • 14 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          Вектор в отличие от массива делает Range-check проверки. Это занимает какое-то время. Про такие конструкции как vector<vector<int> > я вообще молчу.
          В принципе стл весь притормаживает (пожалуй кроме сорта). Но это не повод им не пользоваться.
          • 14 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            Только что проверил - время 10 миллиардов доступов к элементу у вектора и у массива в точности одинаковое (g++ -O2). Про range check первый раз слышу - интересно, зачем его там делать, и почему в случае вылезания за границы этот range check никогда не срабатывает? В debug'е он конечно делается, но мы ведь говорим про нормально скомпилированную программу.
            Про stl тоже не соглашусь - по моим впечатлениям там только set/map тормозят, остальным всегда можно пользоваться ничего не опасаясь.
            • 14 лет назад, # ^ |
                Проголосовать: нравится 0 Проголосовать: не нравится
              хм... интересно. память что вектор проверяет корректность итератора осталась со времени когда писал в MSVS. 
          • 14 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            Вектор делает range-check только когда обращение к елементам через .at() если обращение через operator [] то проверки нет.
14 лет назад, # |
  Проголосовать: нравится +1 Проголосовать: не нравится
Хм... ну вот еще:
Никогда нельзя писать
if (a==b) ...
где a,b - double
потому как иногда , бывает даже такое: (1/(2.0) != 0.5).
Нужно использовать погрешность.

Ну а это из моей практики самая идиотская ошибка:
Если в условии не сказано , что числа целые - то в 99% случаев они действительные. И это нужно очень внимательно предусмотреть.
  • 14 лет назад, # ^ |
      Проголосовать: нравится +5 Проголосовать: не нравится
    Не хочу показаться занудой, но (1/(2.0) == 0.5) :)
    А с советом полностью согласен.
    • 14 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      +1 =)
    • 14 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      там все правильно потому, что иногда такое все-таки бывает 1/(2.0) != 0.5 =)
      • 14 лет назад, # ^ |
          Проголосовать: нравится +3 Проголосовать: не нравится
        условие 1./2.==0.5 всегда истина потому что 0.5 представляется в системе счисления с основанием два конечной дробью (знаков хватает для представления) ,  а вот 1./2.-1./3.==1/.6 ложно ;)
14 лет назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится
В С++ std::map с большим (порядка 10^5) количеством ключей иногда очень долго удаляется (иногда ее деструктор работает в несколько раз дольше, чем все решение задачи). В таких случаях можно избежать автоматического вызова деструктора, создав экземпляр map динамически (оператором new) и не удалять его (это утечка памяти, но нам не важно, ведь мы все равно не собирались удалять его до завершения процесса). Например, вместо map<string,string> dict использовать map<string,string> &dict=*new map<string,string>().