Задать вопрос
  • Как решить эту задачу, используя массив 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 не вложенных цикла.
    Ответ написан
    Комментировать
  • Что я не правильно делаю в тестовом задании?

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

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Это обобщение известной задачи, где пропущено одно число. Там можно, например, вычесть все числа из n(n+1)/2. Или про-xor-ить все числа от 1 до n и все числа в массиве.

    Для двух чисел нужно составить какие-то 2 уравнения, Например, найдите сумму двух чисел и сумму их квадратов: Сумма пропущенных чисел - это n*(n+1)/2 - (сумма всех чисел в массиве). Здесь надо аккуратно не забыть о возможном переполнении (если ваш язык, например, С++). Сумма квадратов: сумма квадратов всех чисел от 1 до n минус квадраты всех чисел в массиве.

    Итак, вы за O(n) двумя не вложенными циклами (один для суммы квадратов 1..n, другой для обработки всех чисел массива) нашли X+Y=A и X^2 + Y^2=B.

    Теперь решите уравнения относительно X и Y: Выразите X через Y из первого уравнения и подставьте во второе. Решите квадратное уравнение и получите:
    X = (A-sqrt(2B-A^2))/2, Y = (A+sqrt(2B-A^2))/2.

    Тут, хоть и есть квадратные корни, они в итоге дают целые числа.
    Ответ написан
    Комментировать
  • Как решить задачу?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Быстрое решение - построить для этого массива суффиксное дерево алгоритмом Укконена (или вот ссылка), потом обойти его, найти самую глубокую вершину, у которой есть более одного ребенка, и вывести путь до нее от корня. Работает за O(n).

    Edit:

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

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

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Если я все правильно понял, то у вас всего 5 кубиков и 3 варианта, на каком ходу зафиксировать кубик. Т.е. всего вариантов 3^5 = 243. Это очень мало - их можно все перебрать. Для этого надо или 5 вложенных циклов, или рекурсивная функция, которой передаются уже собранные числа в массиве, какой следующий кубик перебирать. Если еще не все 5 кубиков собраны, то функция гонит цикл из трех вариантов и для каждого дописывает текущий кубик к массиву, рекурсивно запускается, и удаляет последний кубик, чтобы откатить изменения для следующего варианта. Если все 5 кубиков выбраны, то текущий вариант оценивается и, если надо сохраняется.

    Тут советую написать отдельную функцию проверки, которая копирует массив (или принимает его по значению), сортирует его и тупо проверяет все варианты (Стрит - arr[0] == 1 && arr[1] == 2 ... && arr[4] = 6, пять одинаковых - все числа равыны. 2+3 - первое==второму, третье==пятому или первое==третьему, четвертое == пятому).
    Ответ написан
    2 комментария
  • Как преобразовать слова?

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

    Решается так:
    1) Проверить, что строки равны. Это особый случай
    2) Проверить, что длина одинаковая?
    3) Завести мап символ->символ, пройтись по строкам параллельно и записывать мап[строка1[i]] = строка2[i], если там пусто. Иначе - проверить, что там уже записано то же самое.
    4) Проверить, что различных символов во второй строке меньше 33. Можно с помощью сета, который наполняется в том же цикле, что и в шаге 3.
    Ответ написан
    5 комментариев
  • C#. Есть два массива, как сделать проверку данных на совпадение?

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

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

    Лучший вариант: Пройтись по меньшему массиву и сложить его элементы в HashSet<> (через Add()). Потом пройтись по второму массиву и каждый элемент проверить через метод Contains() у сета.
    Ответ написан
    2 комментария
  • Как разделить все точки на плоскости на пары с минимальным расстоянием?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    После сведения к теории графов есть решение за O(n^3) через венгерский алгоритм (реализация) или через алгоритм посика максимального потока минимальной стоимости (Там реализация, медленнее венгерского метода. Вот решение за n^3, но код готовый я не нашел).

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

    А это уже есть задача о назаначении на матрице расстояний между всеми парами точек: Надо в каждой строке выбрать ровно один элемент так, чтобы в каждом столбце был ровно один элемент и сумма была минимальной.


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

    Пример
    3 вершины (0, 0), (1, 0) и (0, 1).
    Матрица расстояний (с 1e90 на диаганали вместо 0):
    ((1e90, 1, 1),
    (1, 1e90, 1.414),
    (1, 1.414, 1e90)).

    Решение ценой 3.414 (3-ий элемент в 1-ой строке, 1-ый во 2-ой строке и 2-ой в 3-ей)
    ((*, *, 1),
    (1, *, * ),
    (*, 1.414, *)).

    Это значит, что вы берете пары 1-3 2-1 3-2.
    Ответ написан
    Комментировать