Задать вопрос
  • Почему не работают хеши?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Ну хоть бы написали, что за хеши вы тут считаете. Похоже у вас полиномиальных хеш.

    И xhash и gethash написаны с ошибками.

    Давайте посмотрим на xhash. Если l==r, то вернется s[l]*1. Вроде правильно. Если l+1=r, то ваша функция вернет s[l]*p^2+s[l]*p+s[r]. Вряд ли это то, чего вы хотели добиться. Или инициализация перед циклом неверная, или границы у цикла.
    Ответ написан
  • Какой алгоритм для вычисления оптимальной задержки для API и сообщения её ПО пользователя, чтобы не генерировать лишнюю нагрузку?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Это известная и сотню раз решенная задача. Гуглите "exponential backoff" или "Экспоненциальная выдержка".
    Ответ написан
  • Какие есть алгоритмы сортировки и поиска с помощью деревьев?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Самое быстрое и простое - сортировка кучей.

    Теоретически, можно любое search tree использовать, но оно будет медленее, потому что структуры сложнее.
    Ответ написан
  • Где и как используют деревья в программировании?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Само по себе тупо дерево весьма бесполезно. Но как базовая организация данных она встречается много где. Если на него навесить какие-то дополнительные свойства и поддерживать их, то получаются классные штуки.

    Балансированные бинарные деревья поиска - очень популярная структура данных. Используется где угодно, если вам нужно хранить множество или ассоциативный массив чего-либо и менять произвольные элементы.

    Еще деревья часто используются в алгоритмах на строки. Есть такая структура - бор (trie) - позволяет эффективно хранить кучу строк и искать: есть ли такая строка в структуре. Более продвинутые алгоритмы типа Ахо-Корасика, Укконена тоже строят некоторое дерево с дополнительными фишками и позволяют делать крутые вещи, типа искать кучу шаблонов в тексте разом, или моментально находить самую часто встречающуюся подстроку задонного размера.

    Куча (heap) используется для сортировки а так же реализации приоритетных очередей.

    Далее, деревья в смысле графов тоже используются, например, в сети. Маршрутизаторы строят остовное дерево и раздают команды по его ребрам.
    Ответ написан
    Комментировать
  • Какую структуру данных выбрать для подсчета элементов?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вам нужен std::map или std::unordered_map. Самому писать структуру данных не надо.

    Первое будет деревом поиска, второе - хештаблицей.
    Дерево поиска гарантированно будет работать стабильно быстро. Хеш таблица будет работать быстрее, но если вам не повезет, то может работать очень долго. Но предпочтительнее, на мой взгляд, таблица.

    В качестве ключа используйте пару {Тип транспорта, номер маршрута}. В качестве значения - счетчик остановок.

    Еще вам нужен еще один map из тип транспорта-> std::set или std::unordered_set номеров маршрутов.

    Для построения структур один раз приходитесь по всем остановкам и увеличивайте счетчик в первой структуре. Добавляйте маршрут к транспорту во второй структуре.

    Для поиска ответа пройдитесь циклом по всем элементам set из второго map - это все маршруты. Смотрите в первом map'е сколько остановок у этого маршрута и выбирайте максимум.
    Ответ написан
    2 комментария
  • Алгоритм работает не правильно?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Бинпоиск поддерживает текущий отрезок, в котором возможно есть искомый элемент. Смотрит на середину и отбрасывает одну из половин отрезка.

    Вы же как-то пытаетесь реализовать это только лишь с переменной mid. Если надо идти влево, то вы делите mid пополам, как будто бы текущий отрезок от начала массива (Но это не всегда так: после первого же шага вправо начало массива будет уже выкинуто из расмотрения), Потом, при переходе вправо, у вас какой-то бред написан.
    Math.floor((arr.length - mid) / 2) - это что вообще должно делать? Если mid=9, length = 10, вы вообще уйдете в начало массива, хотя должны идти вправо. Если вы хотели взять середину между mid и length, то там должен стоять "+" внутри.

    Но так все-равно не получится сделать. Заведите 2 переменные l и r, как во всех реализациях бинпоиска, считайте mid как середину отрезка, и при выбрасывании одной из половин просто переписывайте l или r на mid+1 или mid-1 (потому что сам mid элемет вы уже рассмотрели и он точно не нужен).
    Ответ написан
  • Как вычислить сумму первых N элементов ряда?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вам уже дана формула n-го элемента.
    В формуле, похоже, опечатка. Должно быть -1 в начале (если подставить n=0).
    Но это не особо важно, все равно первые члены ряда считаются отдельно.

    Соответственно, можно считать текущий элемент через предыдущий, как вы пытались:
    a_k = a_(k-1)*(-x)*(2k+1)/(2k-1)/(2k-1)/(2k-2)

    Только она не работает для k=1. Поэтому 2 первых члена ряда надо прибавить руками, а остальное в цикле i=2..n-1

    Т.е. R вам не нужен, и в коде должно быть:
    u = 1+3*x;
    ...
      u *= (-x)*(2i+1)/(2i-1)/(2i-1)/(2i-2);
      summa += u;


    Да, еще стоит разобрать крайние случаи, если n =0, то надо отдельно вывести 1 (или -1, если мы исправляем опечатку).
    Ответ написан
    4 комментария
  • Как преобразовать массив в новый со следующими значениями?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    print ([("small" if a < 20 else "medium") if a <=30 else "large" for a in a_random])
    Ответ написан
  • Как построить симуляцию луча?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Как это часто бывает в задачах на отражение света, не надо отражать луч. Представьте, что зеркало - это портал в Зазеркалье. Луч идет прямо и, проходя через зеркало, попадает в соседнюю треугольную комнату.

    В этой задаче нужно представить, что вся плоскость замощена треугольниками, прямой луч выходит из одной точки до другой. Сколько сторон треугольников он пересечет - столько отрвжений и сделано.

    Отражения, если вам так хочется, можно делать через вектора. Есть у вас вектор вдоль луча, и вектор вдоль зеркала и нормаль внутрь. Через скалярное произведение можно разложить вектор луча на перпендикуляр и паралледьный к зеркалу. Потом надо развернуть вектор перпендикуляр и сложить их.

    Но в этой задаче это вам не поможет никак - ибо симулировать эти 100500 отражений и квантилионы возможных начальных углов никакого времени не хватит.
    Ответ написан
    2 комментария
  • Как перебрать ходы в двухмерном пространстве?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Можно. Задача решается за O(n^2) динамическим программированием.

    Считайте F(x,y) - лучшую возможную сумму, чтобы закончить в ячейке (x, y).

    База: в левом нижнем углу ответ - число в этой ячейке; за границами - ответ минус бесконечно плохое число (плюс бесконечность, если ищем минимум, например).

    Пересчет F(x,y) = a[x,y] + min(F(x+1,y), F(x,y-1)) - выбираем, с какой стороны выгоднее прийти в эту ячейку.
    Ответ написан
    Комментировать
  • Как осуществить перенаправление траффика или настроить маршрутизацию через код?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Вам надо сделать виртуальное ethernet устройство. Пришедшие на него пакеты надо оборачивать в какой-то ваш протокол, шифровать и посылать дальше на сервер. Сервер же полученные пакеты распаковывает и посылает на внешний интерфейс, подменяя IP адрес отправителя и порт на свои собственные. Пришедшие на этот адрес/порт пакеты сервер оборачивает, подменяет там адрес с портом и посылает назад клиенту. Клиент распаковывает и выдает в систему через виртуальное устройство.
    Ответ написан
    1 комментарий
  • О чем Вам говорит понятие "кольцевой буфер"?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Кольцевой буфер - это очередь с ограниченным размером. Модели очереди хорошо известны.
    Ответ написан
    Комментировать
  • Как исправить скобочную последовательность?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Если это задача такая, то я предполагаю, что там надо удалить минимальное количество скобок, чтобы последовательность стала правильной. Можно только удалять скобки, потому что вместо любого добавления скобки, можно просто вторую пару удалять. Количество действий не изменится. Правда, в ваших примерах оно удалит все скобки.

    Тут можно решать динамическим программированием. Пусть F(l,r) - минимальное количество операций удаления, чтобы сделать из строки с l по r правильную скобочную последовательность.

    База - если l..r - пустая строка - ответ 0.
    Иначе надо рассматривать варианты, что будет с последним символом. Если в конце стоит открывающая скобка, то ее надо удалить - других вариантов нет: F(l,r) = 1+F(l,r-1).

    Если же там закрывающая скобка, то есть 2 варинта: или этот символ удаляем, или берем в ответ. В первом варианте ответ такой-же, как выше. Во втором - надо перебрать, а какой же символ в строке будет открывающей скобкой для данной. Пусть это символ i (там должна стоять открывающая скобка того же типа). Тогда ответ F(l,i-1)+F(i+1,r-1) - ведь части перед парой скобок и внутри их должны тоже быть правильными последовательностями.
    Из всех вариантов надо выбрать минимальный - это и будет ответ для текущего состояния.

    Если хотите восстанвливать саму последовательность, то надо при сохранении минимума еще и сохранять в отдельном двумерном массиве - какой именно из вариантов был выбран (дропнуть последний символ, или какой символ взять ему в пару).

    Ответ к задаче - F(1,n) - для всей строки.

    Это решение потребляет O(n^2) памяти и занимает O(n^3) времени.
    Ответ написан
    2 комментария
  • Алгоритм для минимизации стоимости товаров от разных поставщиков, какие ресурсы изучить?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Можно свести к линейному целочисленному программированию (linear integer programming).

    Индикаторные переменные (0 или 1) - покупаете ли вы этот товар у этого продавца (x_ij).
    Еще переменные - платите ли этому продавцу за доставку (y_j).

    Ограничения:

    y_j >= x_ij
    sum_j (x_ij) = 1

    Целевая функция - мнинимизировать затраты: sum_ij x_ij*c_ij + sum_j y_j*d_j

    Потом решать каким-либо солвером (есть куча быстрых библиотек).

    Еще можно всякие методы отжига или генетические алгоритмы использовать.

    Можно еще полный перебор с отсечениями. Очевидно, что если мы берем какое-то множество продавцов, то каждый из них должен иметь минимальную цену по какому-то товару. Это значит, что можно поддерживать текущие минимальные цены на все товары у выбранных продавцов (+бесконечность, если никто не продает этот товар). Вы можете брать какого-то продавца, только если его цена по какому-то товару меньше. Ну и всякие ранние выходы - если сумма минимальных цен вообще по всем + текущие траты за доставку выше оптимального пока что ответа, дальше добавлять продавцов смысла нет.
    Ответ написан
  • Как решить задачу про графы?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Контрпример - это тот, который опровергает утверждение.
    Утверждение - каждый связный граф имеет хотя бы одну вершину степени 2.
    Т.е. контрпример - связный граф, который не имеет ни одной вершины степени 2.
    Степень вершины - это сколько ребер в нее входит. Можете найти такой граф на картинке?
    Ответ написан
    Комментировать
  • С чем может быть связана ошибка доступа к чтению файла?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    string внутри себя содержит указатели. Поэтому его нельзя просто записывать и читать fread.
    После того, как вы переменную типа string прочитали, там указатели стали указывать туда же, куда структура при записи. А эта память уже может быть занята чем-то другими или не доступна. При выводе вы обращаетесь по этим указателям и получаете крэш.
    Ответ написан
    Комментировать
  • Как решить задачу про ПИН?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Если в условии "трех различных цифр" означает, что все цифры разные, то ответ - количество сочетаний из 10 по 3, умноженное на 3 факториал: C(10,3)*3! = 10*9*8 = 720.

    Логично: есть 10 вариантов выбрать первую цифру, 9 - вторую (исключив вариант повторения), и 8 - третью (минус 2 варианта повторения первой и второй цифры).
    Ответ написан
    Комментировать
  • Выдает ошибку IndexError: list index out of range. В чем дело?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    matrix - у вас пустой список, а вы пытаетесь в [i,j]-ую ячейку что-то записать. Ошибка о том и говорит, что идет обращение по недопустимому индексу.

    Вы после ввода m, n сделайте вот это:
    matrix = [[0 for x in range(n)] for y in range(m)]

    А уже потом ваши 2 цикла с генерацией делайте.

    Ну или в циклах добавляйте в matrix новые элементы:
    matrix = []
    for i in range(m):
      matrix.append([])
      for j in range(n):
        matrix[i].append(random.randint(1,9))
    Ответ написан
    2 комментария
  • Округление при целочисленном делении, как понять?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    (n+k-1) / k даст округление вверх, потому что прибавление k-1 к числителю переваливает его за следующее делящееся на k число после n. Если остаток от деления n на k был не ноль, то мы к этому остатку прибавили k-1 и получили число не меньше k, которое даст +1 к результату деления (что тут и нужно, ведь при неделящемся на k n - округление вверх на 1 больше округления вниз). Если же n делилось на k, то прибавление k-1 не перевалит за следующее делящееся на k число и результат деления не поменяется.

    Округление вниз уже есть встроенное в большинство языков - это просто целочисленное деление. Поэтому сводят к нему.
    Ответ написан
    1 комментарий
  • Как оптимизировать код на Python?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    У вас решение за O(N^2), когда как можно сделать решение за O(N). Тут не в питоне дело, а в плохом алгоритме.

    Надо идти с конца и поддерживать стек убывающих значений температур. При обработке следующего дня надо из стека вынимать значения, пока они меньше или равны текущего. В конце надо положить в стек текущее значение (чтобы считать дельты, надо добавлять пары значение, номер дня).

    Это работает за линию, потому что каждое число один раз кладется в стек и максимум один раз из него удаляется. Этот алгоритм работает за счет того, что мы поддерживаем в стеке только те дни в конце, которые теоретически могли бы быть ответом для какого-то дня (самый левый с большей температурой). Это ровно те дни, которые теплее всех предыдущих дней в конце массива. Если текущий день имеет более высокую температуру, чем что-то в стеке, то это число в стеке уже никогда ни для кого левее ответом не станет. Потому что текущий день находится раньше но имеет более высокую температуру.

    Я не совсем питонист, но вот примерный код:

    def days_till_warming(T):
        counts = []
        stack = []
        for i, curr_temp in enumerate(reversed(T)):
            while len(stack)>0 and stack[-1][0] <= curr_temp:
                stack.pop()
            delta = i - stack[-1][1] if len(stack) > 0 else 0
            stack.append([curr_temp, i])
            counts.append(delta)
        return list(reversed(counts))
    Ответ написан
    Комментировать