• Как решить эту задачу?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    У вас 7 неизвестных и 3 уравнения. Так что однозначно вы найти значения переменных никак не сможете. Но и найти вам надо какую-то сумму. Есть шанс, что как-то комбинируя, складывая, вычитая и домножая левые части этих уравнений можно получить искомую сумму. Иными словами, вам надо вектор (16, 25..100) представить в виде линейной комбинации векторов (1, 2..49), (4, 9..64) и (9, 16..81). Обратите внимание, что там везде получаются суммы трех квадратов равны следующему.

    Вам надо подобрать такие 3 коэффициента, что x*n^2 + y(n+1)^2+z(n+2)^2 = (n+3)^2. Для n=1..7. У вас тут квадратные многочлены от n получаются, равны они в 7 точках, так что они должны быть равны вообще при любых n. Значит, вам надо раскрыть скобки, сгрупировать степени n и приравнять к 0 все коэффициенты.

    Так вы получите 3 уравнения на 3 переменные x, y, z.
    x+y+z=1
    2y+4z=6
    y+4z=9

    Отсюда получается x=1 y=-3 z=3

    В итоге получаете 1*1-3*12+3*123 - это ваш ответ.
    Ответ написан
    2 комментария
  • Какой самый быстрый способ найти позицию последовательности 0-bit заданной длины в int[]?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Зависит от длины n. Если n маленькое то можно прикладывать маску. Байт x содержит 3 ноля в последних битах, если ~x &0x7 == 0x7. Аналогично, сдвигая маску из трех единиц (0x7) можно приложить ко всем позициям.

    Если n большое, то надо чтобы было много нулевых байт в массиве подряд. Тут можно использовать SSE инструкции для массового сравнения байт с нулями.

    Потом, можно еще распараллелить поиск в несколько потоков. Каждый поток ищет последовательность, начинающаюся в отдельном куске массива.
    Ответ написан
    Комментировать
  • В чем заключается суть бинарного поиска неотсортированного массива?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Ну ведь тут массив же отсортирован. Хоть и с приколом: он сдвинут. Можно тем же бинарным поиском найти, где там "разрыв" происходит, а после у вас 2 отсортированных куска. Или сразу модифицировать бинпоиск.
    Представьте, что у вас массив, где сначала идут 1, а потом 0. Можете найти в нем, где 1 переходит в 0?

    Или смотрите так: ищите вы x. Взяли значение a[m]. Можете, посмотрев на a[l], a[m], a[r] и x понять, в какой половине лежит x?

    Edit: ах, тут числа могут быть одинаковыми. Тогда бинпоиск тут не работает. Ибо может быть тест {1,1,1,2,1,1} - и тут можно 2 в любую позицию поставить. И, если вам надо эту 2 найти, то вам придется просмотреть все числа, иначе вы ее не найдете. Бинпоиск возможен, если первое и последнее числа разные.
    Ответ написан
    Комментировать
  • Как на udp сервере подсчитать one-way latency и верменной offset клиента?

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

    В итоге сервер получит 4 таймстампа: сервер отправил, клиент получил, клиент отправил, сервер получил. При этом два серверных и два клиентских - могут быть в разных часах. Поэтому надо взять t4-t1+t2-t3 - и вы получите rtt. Поделите на 2, получите оценку нужной задержки. И это надо сглаживать по многим пакетам.

    Проблема будет, если часы тикают с разной скоростью, а не просто отстают на фиксированное время. Это надо смотреть на динамику t2-t1. Если там линейная регрессия с отличным от 1 коэффициентом получается, то надо это учесть и делить на этот коэффициент t2-t3 в формуле. Но это редко делают. Если время обработки пакета клиентом мало по сравнению с сетевой задержкой, то лишь малая часть этого времени пойдет в ответ ошибкой.

    Однако, если вы часы синзронизируете, то вам надо постоянно пересчитывать отставание по последнему пакету и оценке rtt. И этот сдвиг часов будет изменятся со временем а соответствии с разной скоростью часов.
    Ответ написан
    Комментировать
  • Какой структурой можно повесить lock на диапазон?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Если у вас диапазоны такие маленькие, то можно прямо в классе буфера завести еще и массив mutex-ов. И каждый поток будет их лочить слева на-право по всему диапазону (важно, что каждый поток делает это в одном и том же порядке, а то дедлоки получите).

    Тут "выделение" куска будет не такой тривиальной операцией, как один лок, но зато, никах спинлоков. Система может потоки усипить и будить только когда очередной мютекс освободится.

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

    Тут операция выделения сама по себе будет сильно быстрее. Но это фактически спинлок - каждый поток будет в цикле пытаться выделить себе интервал, пока не сможет. Если ожидается, что потокам придется долго ждать, то надо какие-то стратегии back-off добавлять (спать между вызовами). И вообще спинлоки - это плохо.

    Как сделать это без спинлоков с деревом отрезков - я не придумал.
    Ответ написан
    Комментировать
  • Как показать зависимость скорости от O(nlogn)?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Можно, только надо числа брать побольше. Скажем, 100000 и 1000000. Для полносты картины можно взять несколько точек. Еще возьмите, например, 5000000 и 10000000.

    Но вообще сложность алгоритма обычно доказывают логически. Типа, у вас там n операций с кучей, каждая операция ограничена O(log n) - потому что она проходит по бинарному дереву с менее чем n листьями, а значит, высотой менее log n.
    Ответ написан
  • Ошибка double free or corruption (out) Aborted, как исправить?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вы никакого free и даже delete или new в программе не делаете. Значит ошибка в том, что структуры менеджера памяти как-то портятся. Это значит, что вы пишите куда-то за границы массива.

    Можно попытаться запустить программу в отладчике, или добавить кучу отладочного вывода, чтобы посмотреть, что и как вы портите.

    Подозреваю, что ошибка тут:
    int mli=index(len,ml),mpi=index(len,mp);
    Обратите внимание на второй вызов index. Вы ищите в массиве len значение mp, которое вы нашли в массиве price. Возможно оно возвращает -1 и дальше уже вы пытаетесь что-то делать в векторе по этому индексу, что вряд ли закончится хорошо.
    Ответ написан
    Комментировать
  • Почему постоянно выводится расстояние 0(Алгоритм Дейкстры для городов)?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Вы выводите d[begin_index], это расстояние до начальной вершины. Естественно там 0 будет. А выводить надо расстояние до конечной. Надо end использовать (и выводить после того, как вы end нашли).
    Ответ написан
    Комментировать
  • Как найти кратчайший путь в лабиринте, двигаться в котором можно только вперед и направо?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вы правильно поняли, что у вас вершинами в гарфе являются клетка+направление, по которому пришли.
    Но раз у вас вот это вершины, то вам и пометки о песещении вершины надо делать в трехмерном массиве. А начальных и финальных вершин у вас по 4 штуки: клетка x 4 направления (на самом деле, начинать достаточно только с 2 направлений, но неважно).
    Ответ написан
    3 комментария
  • Какой алгоритм использовать, чтобы: разбить массив чисел так, чтобы суммарная разница между максимальным и минимальным числом была максимальна?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Ага, ДП тут отлично входит. F(n) - ответ на задачу для префикса длины n. Там перебираете длину последней группы x и берете в качесвте ответа max(a[n-x]..a[n-1]) - min(a[n-x]..a[n-1]) + F(n-x). По всем l<=x<=r выбераете максимум. Если n < l, то ответ - минус бесконечность.

    Это будет решение за O(n^2). Что-нибудь за O(n log n) я так сходу придумать не могу.
    Ответ написан
    6 комментариев
  • Как в C++ создать массив с неизвестным числом элементов?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Можно через new[] выделить массив:
    cin >> n;
    int *array = new int[n];
    // ввод, и работа с массивом.
    
    // не забудьте в конце удалить выделенную память.
    delete[] array;
    Ответ написан
  • Как оптимизировать код с++ с рекурсией в времени?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Можно попробовать сделать микрооптимизации: функция F реализуется одним циклом (делите, пока делится на 10, потом берите последнюю цифру). S тоже можно считать циклом, а не рекурсией.

    Но скорее всего, этого не хватит. Это решение за O(q*log(q)). Ограничения на числа в условии не видно, но если там что-то порядка 2000000000, то ваша программа будет считать несколько секунд.

    Надо хорошенько подумать и применить математическую хитрость. Надо как-то считать числа в интервале p...q пачками, а не каждое отдельно.

    Что такое функция F? Это последняя ненулевая цифра в числе. Давайте вместо суммы значений F счиатать, сколько чисел из интервала дадут вот такое вот значение? Ну просто по последней цифре сложно сказать, сколько там чисел, а вот если еще зафиксировать количество пропущенных в конце нулей, то уже становится понятно, как подсчитать это. Вот допустим, вы считаете последнюю цифру d и там должно быть 3 нуля. Тогда вы ищети числа вида "xxxd000". Или их можно представить в виде d*1000+x*10000 для произвольного неотрицательного x. И вот вам надо подсчитать сколько таких чисел в интервале [p,q]. Ну решите 2 уравнения: d*1000+x*10000 >= p и d*1000+x*10000 <= q

    Таким образом вы за несколько арифметических действий и одну проверку можете подсчитать, сколько чисел вида "xxxd000" будут в интервале. Осталось циклом перебрать d от 1 до 9 и количество нулей от 0 до длины q. И вот у вас решение за O(log(q)).

    Edit:
    Вот код быстрого решения:
    int S(int p, int q) {
      int sum = 0;
      for (int d = 1; d < 10; ++d) {
        for (int tens = 1; tens <= q; tens *= 10) {
          int left = p - d*tens;
          if (left < 0) left = 0;
          else left = (left + 10*tens-1)/(10*tens);
          int right = q - d*tens;
          if (right < 0) right = -1;
          else right /= 10*tens;
          sum += d*(right - left + 1);      
         }
      }
      return sum;
    }
    Ответ написан
  • Как устроен вывод в задаче?

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


    не сумма всех взятых ребер, а стоимость максимального из них.

    1 2 (2) и 2 3 (1) - максимальная стоимость 2 (max(1,2)).

    1 3 (3) - максимальная стоимость 3 max(3). 3 больше 2, значит ответ выше лучше.

    Так задача легче, чем с суммой.
    Ответ написан
    8 комментариев
  • Какую формулу использовать?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Можно делить на цело в конце. 110*300/330 даст ровно 100. Если же в котле осталось не делящееся нацело количество монет, то будет округление вниз: для 301 монеты тоже получится 100 вместо 100.(3).

    Надо хранить долю юзера в виде рационального числа - отдельно числитель и знаменатель.
    Ответ написан
    Комментировать
  • Справится ли алгоритм с задачей по поиск слов в словаре?

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

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Внутренние циклы выполняют суммарно максимум 8(r-l-1) операций. На каждой итерации внешнего цикла r-l уменьшается на 2. Т.е. всего операций будет 8(n-2)+8(n-4)+8(n-6)...

    Можете эту арифметическую прогрессию подсчитать и оценить?
    Ответ написан
    Комментировать
  • Как вернуть двумерный массив?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    int masInt[3][5] - вот такие массивы c фиксированными размерами на самом деле хранятся одним куском и индексацию компилятор вычисляет сам. Это не int**, а int[][5]. Только этот тип нельзя вернуть из функции.

    Что бы вернуть именно указатель на указатель, вам надо его так и завести и не забыть выделить по строкам:
    int** masInt = new int* [3];
    for (int i = 0; i < 3; ++i) {
      masInt[i] = new int[5];
    }


    Не забудьте только потом удалить все это добро через delete[]:
    for (int i = 0; i < 3; ++i) {
      delete[] array[i];
    }
    delete[] array;


    Но вообще, лучше не парить себе мозги и возвращать std::vector<std::array<int,5>>.
    Ответ написан
    1 комментарий
  • Как реализовать многопоточность на C++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Тут не надо никакой многопоточности. Все такие симуляции выполняются в один поток с очередью событий.

    Вот в 0 секунд у вас I1..I5 сгенерировали заявки, они пападают в накапители и сразу же из них в каналы. В 3 секунды K1 обработал заявку и свободен. Взял одну из накопителя. В 4 секунды K2 освободился, взял заявку из накопителя. В 5 секунд источники снова сгенерировали заявки... и т.д. Это можно просимулировать.

    Реализуется это с помощью приоритетной очереди событий. В нее вы складываете новые события, а в основном цикле достаете оттуда событие с минимальным временем. На c++ это будет что-то вроде:
    std::priority_queue<pair<int, Event>, std::vector, std::greater> queue
    .

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

    Например, источник в момент создания кладет в очередь событие "в 0 секунд я создам заявку". При выполнении этого события, во-первых, создается и кладется в очередь новое событие "в t+5 секунд я создам заявку". Во-вторых, надо посмотреть, куда заявки из этого источника попадают. Если это накопитель, то заявка пихается в него.

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

    Класс канала при получении заявки создает событие во время t+время обработки заявки, что он освободится. При вы полнении этого события канал смотрит, к чему он подключен и если там не пустой накопитель, то забирает оттуда первую заявку.

    Класс Event должен как-то запоминать какой объект это событие выполняет. А основной цикл должен этот код вызывать (и передавать туда время события).
    Ответ написан
    Комментировать
  • Инструмент для сохранения всех вариантов сочетаний по заданной маске?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Есть. Называется python + модуль itertools.
    import itertools
    import string
    
    def generate_strings(length):
        chars = string.ascii_letters + string.digits
        for item in itertools.product(chars, repeat=length):
            yield "".join(item)
    
    for string in generate_strings(3):
        print(string)


    Для 8 символов поменяйте 3 в коде на 8.
    Ответ написан
    Комментировать
  • Как получить хендл без OpenProcess?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    У какого-то левого чужого процесса вы handle никак "украсть" не сможете, ибо в винде хандлы отдельные для каждого процесса. Одни и те же циферки handle в разных процессах могут означать разное. Поэтому даже если вы залезете в память процесса и данные получите, без какого-то содействия от системы вы чужой хандл никак использовать не сможете.

    Если же это все ваши процессы, то можно воспользоваться функцией DuplicateHandle. Только надо выставить правильные права доступа для хендлов и процессов.
    Ответ написан
    Комментировать