Задать вопрос
  • Задача на многопроцессорное программирование в c?

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

    Как решать задачу паралелльно: Разбейте всю строку на N (количество потоков) частей и каждый поток отдельно для каждой части найдет ответ внутри нее. А также две велечины: Самый последний символ '<', самый первый симовл '<' и вообще, есть ли они в этом куске.

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

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

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

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

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Возьмите функцию f(x)=(1+1/x)^(1+x)-x.

    Через матан (взять производную, убедиться, что она всегда отрицательна. Подсчитать значение f(x) при x=1) можно убедится, что у функции нет корней, кроме одного на отрезке (1, +inf), ведь она всегда убывает и для единицы она положительна.

    Теперь мы знаем, что только одно число удовлетворяет этому уравнению.

    Судя по всему, корень не пи: https://www.wolframalpha.com/input/?i=%281+%2B+1%2...

    То, что он где-то там можно понять, если подсчитать функцию в точках 3.1, 3.2, 3.3 - между двумя, где функция меняет знак, и лежит корень.
    Ответ написан
    Комментировать
  • Как вырезать квадраты из матрицы?

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

    Но если вам так надо, заведите функцию, которая вырезает квадрат с заданными координатами и размерами (и в двух вложенных циклах по i и j от 0 до 2 запускайте ее от координат (3*i, 3*j).

    Функция заводит массив нужного размера и для всех i,j копирует в ячейку [i,j] значение из большой матрицы из ячейки [i+offset_x, j+offset_y].
    Ответ написан
    Комментировать
  • Как правильно написать условие проверки для функции?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Эта функция не определена при x < 0 или 1-cos(x) = 0. Т.е. Если x < 0 или x= pi/2+2pi*k.

    Ф программе вычисляйте функцию по шагам. Сначала знаменатель, если он оказался 0 - not defined. Иначе смотрите, что числитель можно вычислить (x>=0).
    Ответ написан
  • Как найти точку, между двумя точками?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    векторная формула: A + (B-A)/sqrt(|A-B|)*3

    В числах
    x = Ax+(Bx-Ax)*3/sqrt((Ax-Bx)^2+(Ay-By)^2)
    y = Ay+(By-Ay)*3/sqrt((Ax-Bx)^2+(Ay-By)^2)
    Ответ написан
    2 комментария
  • Есть ли метод генерации большого простого числа с факторизацией p - 1?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Можно такой подход: Сгенерируйте два случайных простых числа длиной n/2 бит (Генерируйте случайное число, пока не получили простое). Потом перемножте их, прибавьте 1 и проверьте, что тоже результат простой.

    Для этого надо уметь относительно быстро проверять что число простое. Можно использовать метод Миллера-Рабина. Он вероятностный, но увеличивая число итераций можно достичь произвольно маленькой вероятности ошибки.
    Ответ написан
    Комментировать
  • Как решить эту задачу, используя массив char'ов?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Ну... читайте по одному символу. Можно считать, допустим, начала слов. Что такое начало слова? Это символ-буква, перед которым стоит не буква. Все, что вам надо хранить - это был ли буквой предыдущий символ. Если предыдущий не был, а текущий - является, то прибавляете 1 к ответу. Еще надо аккуратно рассмотреть случай слова в самом начале (т.е. фактически прибавляете 1 если текущий - буква и позиция == 0 или предыдущий символ - не буква).
    Ответ написан
    Комментировать
  • Как реализовать определённые функции в кликере?

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

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

    Т.е. вся логика на клиенте, но она продублированна и проверяется на сервере (например, проверка, что нет 10^20 кликов за секунду, что очков хватало на покупку апгрейда).

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

    Записи в базу данных о рекорде очков, о ачивках или что вы там защитить хотите, сервер делает только согласно своему видению состояния игры. Игрок себе может что угодно нарисовать, и тут вы ему никак не помешаете.

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

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

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

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

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Если клетка может иметь 13 различных состояния, то надо log_2(13)=3.7004... бит. Т.е. если хранить каждую клетку отдельно, то она будет 4 бита.

    Дополнительный цвет клетки удвоит количество возможных вариантов. Будет нужно на 1 бит больше (log2(13*2)=log2(13) + log2(2) = log2(13)+1).

    Запомните, количество бит = логарифм от количества вохможных вариантов. Потому что каждый бит, имея 2 значения, умножает количество возможных вариантов значений на 2.
    Ответ написан
    3 комментария
  • Как найти угол между средней линией и катетом в треугольнике?

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

    Из координат можно найти все тригонометрические функции - косинус, синус, тангенс... Из них потом уже можно получить значение угла в градусах/радианах через обратные тригонометрические функции, например арктангенс (atan в решении). Она по определению возвращает угол если ей передать значения арктангенса.

    Чаще всего используют именно арктангенс, потому что, в отличии от косинусов/синусов, он хорошо работает для любого угла (у арксинуса, например, невозможно различить 45 и 135 градусов - значение синуса одно и то же). У арксинуса и арккосинуса нужно добавлять какие-то проверки сверху для решения неоднозначностей.

    Почему в задаче такой ответ? atan() передаются косинус и синус угла, возможно растянутые на один и тот же коэффициент. Координаты точки М - (1/2 AB, 1/2 BC), ведь это середина AC. Представьте перпендикуляр из точки М на ость OX(BC). В получившемся треугольнике будет прямой угол, гипотенуза BM и катеты с длинами 1/2 AB, 1/2 BC. Соответственно, косинус/синус искомого угла будут 1/2/AM*AB, 1/2/AM*BC. Теперь вспоминаем, что atan() можно передавать значения, умноженные на константу. Вот пусть константа будет 2/AM. Тогда остаются AB и BC.

    Еще, можно смотреть на atan() так - передайте ему координаты конца вектора и он вернет угол между OX и вектором.
    Ответ написан
    1 комментарий
  • Как в диапазоне дат посчитать рабочее кол-во времени?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Если не нужны праздники, высокосные секунды и вот это вот все, То я бы делал так:
    1) Сначала привести времена начала и конца к одному и тому же времени суток.
    Отмотайте время конца до полночи назад - прибавьте пересечение отрезка [0, end_time] c [7:00, 22:45] к ответу (если дата конца рабочая). Также отмотайте время начала вперед до полночи, также учитывая работчее время (если дата начала рабочая.
    При этом к дате начала прибавьте 1, а от даты конца 1 вычтите. Отдельно рассомтрите случай, если даты начала и конца одинаковые.

    Тут нужно будет по дате уметь определять рабочая ли она (получать день недели стандартной функцией).

    2) Теперь осталось подсчитать, сколько рабочих дней между двумя датами (включая их). Я бы тупо вычел времена полдней этих дат друг из друга и поделил на 60*60*24 секунд, чтобы узнать сколько суток прошло. Теперь еще надо определить дни недели начала и конца.

    Далее, также как с временем, отматываем дату начала до следующего понедельника, а дату начала до предыдущего воскресенья. Прибавляем к ответу (рабочее время в сутках)*(max(6-номер_дня_недели_начала, 0)+min(номер_дня_недели_конца, 5)). Теперь считаем сколько осталось полных недель (вычитаем сдвинутые даты друг из друга в днях и делим на 7) и прибавляем столько полных рабочих недель. Особый случай, если начало и конец в одной неделе (разница между ними <= 7-номер_дня_недели_начала).
    Ответ написан
    Комментировать
  • Как праильно определить лотерейные билеты в соответствии с условиями задачи?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    И меня не устраивает "единственный" проблемный отрывок кода:
    if ndata[i] % 2 != 0 and nf % 2 != 0: lucky += 1

    Там вообще какой-то бред написан. При чем тут проверка на четность вообще?!

    Вам надо подсчитать солько чисел из trda есть в ndata и вывести Lucky, если насчитали хотя бы 3 (перечитайте же условие задачи).

    Соответственно должно быть что-то вроде
    if nf == ndata[s]: cnt+=1
    ...
    if cnt >=3:  print('Lucky')
        else: print('Unlucky')


    Еще у вас вложенные циклы по одной и той же переменной i, может в питоне так и можно, но это обычно очень плохая идея.
    Ответ написан
    Комментировать
  • Простая производная?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Это производная комбинации: (f(g(x)))' = f'(g(x))*g(x).

    В вашем случае f(z) = z^2, g(w)=y-w*x.

    f(g(w)) = f(y-w*x) = (y - w*x)^2

    f'(z) = 2z, g'(w) = -x

    Подставляем в первую формулу:
    2(y - w*x)*(-x) - ровно то, что написано в книге.
    Ответ написан
    Комментировать
  • Как определить все способы выплаты суммы n с помощью монет достоинством в 1, 5, 10, 15, 20, 50 копеек?

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

    Решение через динамическое программирование:
    int Count(vector<int> coins, int n) {
      vector<int> cnt(n+1, 0);
      cnt[0] = 1;
      for (int i = 0; i < n; ++i) {
        for (int coin : coins) {
          if (i+coin <= n) cnt[i+coin] += cnt[i];
        }
      }
      return cnt[n];
    }
    Ответ написан
    9 комментариев
  • Как решить задачу?

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

    Понять те формулы можно примерно так. Съели мы первый куст, перешли ко второму. Теперь перенумеруем их, что останется? Та же самая задача, только с n-1 кустом. Только все кусты сдвинуты на k позиций и один номера у них на один уменьшены. Т.е. можно взять тот самый куст который при n-1 останется и найти, какой у него был номер до сдвига.
    Ответ написан
    Комментировать
  • Как для каждого делителя из одного массива найти делители из другого массива с остатком 0?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Если я правильно понял задачу, то надо подсчитать для каждого i
    sum_{j=1..n} (i%j?1:0) % 2.

    Или - есть n ламп в ряд изначально не горящих. Переключаются каждая первая, каждая вторая, третья и т.д. Вопрос - а какие лампы горят в конце.

    Разверните условие. Не переключайте каждую 1-ую, 2-ую и т.д. лампу, а подсчитайте для каждой лампы, сколько раз она будет переключена (потому что переключать их все по одной - это медленно. Надо как-то агрегировать вычисления)?

    Лампа будет переключена ровно столько раз, сколько делителей у ее номера. Иными словами - вам надо понять, четное ли количество делителей у каждого числа. Вспоминаем, что любое число представимо в виде разложения на простые множители: p1^k1*p2^k2* ... pm^km. Можно подсчитать количество делителей - это будет (k1+1)(k2+1)...(km+1), ведь каждое простое число может входить в делитель в степени от 0 до ki включительно.

    Теперь, в каком случае это число будет нечетным? Только если все ki четные. А это значит, что число - полный квадрат (все степени четные же. Берем корень, делим степени пополам, получаем целое число).

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

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

    Для всех интервалов добавить в массив точек пары {время начала, +1} и {время конца+1, -1}. Это массив точек - границ вакансий на оси времени (прибавляем 1 к времени конца, потому что последняя секунда включена в интервал). Потом сортируем этот массив. Теперь одиним проходом можно выделить из массива все отрезки времени и сколько на них было открыто вакансий.

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

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

    Еще можете посмотреть предыдущий ответ вашему товарищу по курсу: В чем ошибка в алгоритме поиска количества интервалов?
    Ответ написан
  • Как правильно получить отрицательный результат подстроки?

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

    Ваш код, например посчитает палиндромом строку "aab".
    Потом, тут еще зачем-то бинпоиск присобачен. Зачем, вообще непонятно.
    И еще ваше решение слишком медленное. Тут сложность порядка O(n^2 log n), что для 200000 ни в какие ограничения не влезет.

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

    решение

    Надо проверить, есть ли 2 подряд идущих одинаковых символа. Если есть - лексикографически минимальная такая пара - ответ.
    Иначе, надо проверить, есть ли тройка символов, где первый равен третьему. Из всех таких надо выбрать лексикографически минимальную.
    Если и таких нет, то ответ "-1".

    Задача решается за 2 не вложенных цикла.
    Ответ написан
    Комментировать