Задать вопрос
  • Как рендерить dx3d11 в dx3d9?

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

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Координаты центра ромба {x,y} - {130/2*(x-y), 84/2*(x+y)}

    Эту формулу можно вывести, например, не зная вообще ничего. Просто проведите все вертикальные линии через все центры ромбов. Какие ромбы лежат на одной прямой? Немного посмотрев, можно заметить, что это те, у которых разность координат одинаковая. Аналогично, проведя горизонтальные линии - можно заметить, что на одной горизонтали лежат ромбы с равной суммой координат.

    Далее надо найти координаты нескольких прямых и можно вывести формулу.

    Второй вариант - через геометрию векторов (это линейная алгебра, или еще нет - как это в школе-то называется вообще?). Нарисуйте вектор из ромба {0,0} в ромбы {1,0} и {0,1}. Ясно, что ромб с координатами {x,y} можно получить сложив x раз первый вектор и y раз второй. Подставляя координаты получите ту же формулу.
    Ответ написан
    Комментировать
  • Как найти слово, гарантированно отсутствующее в наборе?

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

    Если вы видите, что у вас однобуквенных слов меньше, чем букв в алфавите - то можно выдать однобуквенное слово. Иначе, если двух-буквенных слов меньше |alphabet|^2, то можно выдать двубуквенное слово. И так далее. Вот нашли вы минимальную длину.

    Чтобы найти и само слово, заведите битмап размером со сколько у вас слов. Потом пройдитесь по словам и если слово нужной длины, поставьте 1 в битмапе с номером равным строке, если ее интерпретировать как число в |alphabet|-ой системе счисления (самый младший символ равен цифре 0). Если число переваливает за размер битмапы, то можно текущую строку проигнорировать. Потом найдите любой 0 бит в битмапе. Его номер переведите назад в |alphabet| систему счисления.

    Пример. Алфавит - {a,b}. Слова: "a", "b", "aa", "ab", "bb".

    Мы видим 2 однобуквенных слова. Никак. 3 двухбуквенных, но 3 < 2^2 - значит можно выдать двубуквенную строку.

    У нас 2 символа в алфавите, интерпретируем a=0, b=1. "aa" = 0, "ab" = 1, "bb" =3. В битмапе останется пустым индекс 2. Это 10 в двоичной системе или "ba" в строках - это и есть ответ. Да еще и лексикографически минимальный.

    Если слова могут повторятся, то можно чуть изменить решение: точно также перенумеруйте все возможные слова в вашем алфавите. Сначала будут однобуквенные, потом двубуквенные и т.д. При переводе строки в индекс - также переводите из |alphabet|-ичной системы счисления. Но для слова из l символов прибавляйте смещение |alphabet|^(l-1)+|alphabet|^(l-2)+... |alphabet|^1. Точно так же, если в процессе вычисления видно, что индекс не поместится в битмапу (больше количества строк), то можно забить на эту строку. Поэтому же можно сразу пропускать слишком длинные слова.

    Опять же, помечайте бит в битмапе. Потом найдите первый нулевой бит. И назад преобразуйте в строку - сначала найдите смещение (суммируйте степени |alphabet|, пока они не перевалят за текущий индекс). Так вы поймете, сколько символов у вас в строке. Вычтите смещение и переводите индекс в |alphabet|-ичную систему счисления.

    Этот вариант в среднем может работать чуть дольше, но все так же очень быстро.

    Еще, оба эти варианта самые экономные по памяти.
    Ответ написан
  • Как создать новый поток c++?

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

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

    Иногда, если ваша лямбда stateless (не захватывает никаких переменных), то некоторые компиляторы (vs, например) смогут эту лямбду перобразовать к указателю на функцию. Но это не ваш случай, потому что у вас захватываются переменные - вам же надо как-то recoil и mouseManager использовать изнутри лямбды.

    Если очень хочется лямбду, то чисто теоретически, ваши переменные можно засунуть в глобальные переменные. И тогда лямбда не будет ничего захватывать. Но это дичайший говнокод - так делать не надо.
    Ответ написан
    1 комментарий
  • Почему квадрантовое дерево медленнее брутфорса?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Это дерево квадрантов (оно же kd-дерево) плохо работает для запроса "найди все точки"), если точки в нем лежат кучно и почти все попадают в ответ. В этом случае вы, как и в наивном решении, проверите почти все точки, но при этом потратите в несколько раз больше времени на накладные расходы - проверку пустых листов и обход дерева.

    Еще, ваше дерево, если точки лежат кучно, создает очень много пустых вершин. Представьте, что все точки лежат очень близко к левому нижнему углу. Вы разобъете квадрат на 4 части, но 3 из них пусты. Вы повторяете эту операцию, пока квадраты не станут совсем маленькими и не разобьют точки на несколько групп.
    Первая оптимизация - не добавлять точки по одной, а обрабатывать их группой. Если в текущей вершине точек слишком много - надо найти медианную точку по горизонтали, а внутри каждой группы медианную по вертикали. И будут у вас 4 прямоугольника на месте изначального, но они не будут выравнены как 4 четверти квадрата. Но зато будут всегда делить пополам.

    Вторая оптимизация - если вы видите, что bounding rect текущей вершины лежит целиком в запросе - надо просто вернуть все точки.

    Но есть другая структура, которая будет работать лучше в вашем примере, хоть и занимать в log n больше памяти.

    Вам нужно дерево отрезков бинарных деревьев поиска (можно использовать std::set).
    Заведите дерево отрезков по OX, где каждая вершина будет упорядоченное по OY set всех точек попадающих в данный отрезок по X.

    При запросе вы разбиваете отрезок по X запроса на Log n отрезков-вершин в дереве отрезков (это те вершыны, которые надо взять в запрос по ссылке выше) Далее в каждом из этих Logn сетов можно через lower_boundary и upper_boundary получить итераторы начала и конца всех точек в вашем запросе.

    Т.е вы можете получить все точки за O(log n). Правда, какая-то обработка их уже будет O(n) в худшем случае - вся ассимптотика портиться. Но если вам нужно только их количество, то вы можете найти расстояния между двумя итераторами за константу и не надо точки никуда копировать в вектор.

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

    Еще, оптимизация, если у вас lower_bound оказался равен upper_bound, то не надо эту пару итераторов (пустой интервал) класть в массив ответа.

    Еще один бонус этой структуры, что можно быстро удалять/добавлять/менять точки и все остается балансированным. Но, в отличии от kd-дерева, оно занимает в log n раз больше памяти и операция поиска всегда занимает O(log n + ответ), что может быть чуть медленее лучшего случая kd дерева, где вы можете сразу же закончить поиск, если очевидно, что в ответе ничего нет. Зато в худшем случае будет работать быстрее.
    Ответ написан
    Комментировать
  • Найти номер первого и последнего вхождения элемента в масссив?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Что у вас там за цикл по k после вызова бинприска? Именно он и тормозит делая вашу программу работать за nm вместо m log n.

    И да - используйте lower_bound и upper_bound. Это в точности то, что вам нужно.
    Ответ написан
    Комментировать
  • Как вывести формулу?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Сначала заменой x=x'+x0, y=y'+y0 можно убрать коэффициенты D и E и считать, что центр лежит в точке {0, 0}.

    Дальше надо подобрать такой угол поворота, что коэффициент при xy станет нулем. Тогда останется что-то вроде A'x^2+C'y^2 + F' = 0 - а значит эллипс выравнен вдоль осей и это был искомый угол.

    Подставляя формулы поворота системы координат x=x' cosa-y' sina и y=x' sina + y' cosa и приводя слагаемые можно составить уравнение на этот самый коэффициент перед xy. Он будет озависить только от A,B,C и sina, cosa. Далее это тригонометрическое уравнение надо причесать и решить. Вам придется воспользоваться вот этой формулой для котангенса двойного угла: maxresdefault.jpg.

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    node = nullptr;

    Этот код переписывает значение указателя node, который является аргументом функции, переданным по значению. Фактически, вы затираете локальную переменную.

    Кроме того, ваша функция пытается переписать все указатели нулями, но нигде не делает delete - поэтому там у вас утечка памяти.
    Ответ написан
  • Как организовать такую запись с помощью класса?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    System - это глобальный экземпляр класса, который содержит член out, у которого есть метод println.
    class SystemType {
    public:
      class Out {
          public: void println() {
              cout << "haha";
          }   
      } out;
    } System;
    Ответ написан
    Комментировать
  • Как построить контекстно-свободную грамматику по мультиграфу автомата с магазинной памятью?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Нет, приведенный автомат принимает язык {a^i b^j c^k | i=j, i>=1, k>=1} - букв c может быть сколько угодно, никак не связанно с количестовом букв b.

    Первый переход всегда кладет в стек #. Потом на каждую поглощенную a исходной строки добавиться A в стек. Потом b будет поглащаться вместе с A из стека. Потом поглатиться с из строки и # из стека. В конце может поглотиться сколько-то c.

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

    Сначала составьте граматику для языка {a^ib^i, i>=1}. Потом ее можно легко преобразовать чтобы дописывались c.

    Граматика для такого языка будет, например:
    S -> aSb
    S -> e

    Для дописывания c в конце:
    Z->Zc
    Z->S
    Ответ написан
    Комментировать
  • Найти количество чисел меньше заданного?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Куча ошибок. Вы читаете запросы в массив B и больше нигде не используете. Конструкция A{m<i] вообще удивительна. Массив надо отсортировать.
    Ответ написан
  • Что не так с синусом?

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

    Надо или копировать с изменениями в новое изображение, или менять направление прохода в зависимости от знака синуса.
    Ответ написан
    5 комментариев
  • Почему операция 0.0 / 0.0 выдает ошибку?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    В какой книге написано про nan? По стандарту C++ деление на ноль - это неопределенное поведение:

    If the second operand is zero, the behavior is undefined,


    Правда, есть одно исключение:
    except that if floating-point division is taking place and the type supports IEEE floating-point arithmetic


    Вот только этот стандарт IEEE 754 не постулируется стандартом C++ (потому что зависит от аппаратной реализации чисел с плавающей запятой).

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

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Чтобы выводилась буква 't' вам надо обращатся ко второму символу второй строки (str[1][1] - сработает, как вы и ожидаете). Потому что у вас в коде в строках первые символы - пробелы.

    Похоже, вы вставили отредактированнй пример, ибо он даже не скомпилируется - для третьей строки не хватает места. В " three" - 6 символов, плюс терминирующий '\0', когда как массив длинной только 6. Это будет ошибка компиляции.

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Есть 2 решения.

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

    Быстро получать наибольший общий делитель можно за логарифм с помощью структуры данных дерево отрезков. Общая сложность будет O(n log n).

    Второе решение такое: Раз числа на отрезке все делятся на что-то больше 1, то все они делятся на какое-то простое число. Значит задача состоит в том, чтобы найти самый длинный отрезок из чисел, делящихся на одно и тоже простое число. Значит вам надо разложить каждое число в массиве на простые множители и работать с ними отдельно. Далее, вам достаточно просто хранить для каждого простого множителя, какая длина у самого последнего отрезка из чисел с этим делителем и на какой позиции он закончился. Когда вы нашли, что текущее число делится на p, вам надо или начать новый отрезок или добавить текущую позицию к последнему отрезку.

    Общая сложность у этого решения будет O(n sqrt(a)), но его можно ускорить, если предподсчитать для каждого числа от 1 до A один из его простых делителей.
    Ответ написан
    3 комментария
  • Как перемешать массив в псевдослучайной последовательности?

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

    Или можно сортировать хеши, полученные из id тега и id статьи. Например, можно подсчитать tag_id*article_id % n.
    Ответ написан
  • Как вывести полярное уравнение эллипса, гиперболы, параболы?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Берете уравнение вашей функции в виде F(x,y)=0. Подставляете туда x=x0+r*cos(fi), y=y0+r*sin(fi). Выражаете r через fi - вот и уравнение в полярных координатах.

    Тут будет много формул. Во-первых, уравнение F(x,y)=0 надо составить через через эксинцесинтрет и фокальный параметр. Координаты фокуса тоже надо через них выразить. Во-вторых выражение с косинусами и синусами придется хорошенько причесать используя всякие тригонометрические тождества.
    Ответ написан
    Комментировать
  • Почему не работает такое решение?

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

    Чтобы через DFS найти отрицательный цикл - придется перебирать ВСЕ циклы. Для этого надо не помечать вершины как visited. Правда, работать будет очень медленно и почти гарантированно не пройдет по time limit, ибо циклов в гарфе может быть экспоненциально много.

    Edit, вот вам пример. В графе только один отрицательный цикл 1->2->3->1. Но есть еще ребро 1->3. Если вы начнете из 1-ой вершины, потом возьмете ребро 1->3, то дальше вы из вершины 3 никуда не сможете пойти, уберете ее из стека и пометите как visited. Далее вы рассмотрите ребро 1->2 а потом из вершины 2 ребро 2->3 вы пропустите, потому что вершина 3 уже visited.

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Очередь с приоритетом реализуется на основе кучи или бинарного дерева поиска (set). В первом случае удаление делается так: Меняете местами первый и последний элемент в куче. Удаляете последний. Потом просеиваете первый элемент вниз, чтобы он встал на свое место. Во втором случае надо просто удалить из сета элемент begin().
    Ответ написан
  • Какую структуру данных надо использовать что бы посчитать уникальные ip в огромном количестве?

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

    Сортировать можно разными способами. Например, читать кусками сколько помещается в память, отсортировать как угодно, записать на диск. Потом получившиеся отсортированные куски можно объединять, как в сортировке слиянием.

    Еще можно использовать radix sort.

    Если есть еще и ограничения на использование места на диске, и в память оно не помещается, то можно воспользоваться фильтром Блума. Заведите его на сколько у вас там памяти хватит. Возьмите много хеш функций. Ну и потом за один проход проверяйте, есть ли уже считанный адрес в фильтре. Если нет - добавляйте и увеличивайте счетчик. Вот только это вероятностый метод и он может недосчитать чего-то из-за ложноположительных срабатываний блум фильтра.
    Ответ написан
    Комментировать