Задать вопрос
  • Как решить подобную задачу?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Ошибка, если интересно, в том, что в коде написан & вместо %. Соответственно, пропускаются не числа, которые не делят n, а числа, дающие не 0 в побитовом И с n.

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

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

    Совсем быстрое решение - это динамическое программирование по бинарным цифрам корня. Это весьма сложный алгоритм. Сработает, в общем-то, для n до 2^64. Считайте F(l,f) - количество способов как-то расставить первые l бит числа, т.ч. все биты, единичные в n, взяты по 0, и число не превосходит корня из n, а f - флаг, означающий, что число уже строго меньше корня.

    Легче считать это циклом снизу вврех. Смотрите, какую цифру можно дописать к (l,f): если в n стоит 1 в этом бите - то только 0. Иначе, можно дописать 1, только если f=1 или в sqrt(n) стоит 1 в этом бите. Новый флаг f' будет 1, только если f=1, или вы поставили 0, а в sqrt(n) стоит 1.

    Потом ответ надо домножить на 2 и вычесть 1, если (int)sqrt(n) & n == 0.
    Ответ написан
    1 комментарий
  • Как убрать дублирование чисел в бинарном файле на си?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    С чего вы взяли, что туда записывается два числа 7?
    Туда записывается одно число размером в 4 байта, которое, если его интерпретировать как строку, выглядит как "7 7 ".

    Вы числа читаете и пишите в бинарном формате. Соответственно, файл input.bin у вас должен в hex редакторе выглядеть "0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x07...", а не то, что у вас.
    Ответ написан
  • Как найти наикратчайшие пути взвешенного орграфа, представленного матрицей инцидентности, используя алгоритм Дейкстры?

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

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

    Кстати, у вас матрица инцидентности неправильная: должно быть по 2 числа в каждой строке. Обычно ставят -цену у начальной вершины и +цену у конечной.
    Ответ написан
    4 комментария
  • В чем разница записи массива через указатели?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Проблема в том, что * выполняется перед вычетанием. *(current-1) - это предыдущий элемент. (*current-1) в плохой версии - это текущее значение минус 1.
    Ответ написан
    Комментировать
  • Как преобразовать char* содержащий символы unicode?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вам надо \uXXXX преобразовать в char16_t? Можно это руками делать. Берете по 6 байт из строки. Последние 4 руками преобразуете из 16ричной системы. Если символ от a до f, то прибавляете к нему 10-'a'. Если от 0 до 9 - 0-'0'.

    Удобно это циклом делать, сдвигая ответ на 4 бита влево и прибавляя новый символ:
    std::wstring Parse(const std::string encoded) {
      std::wstring result;
      for (int start = 0; start < encoded.length(); start += 6) {
        if (encoded[start] != '\\' || encoded[start+1] != 'u') return result // строка неправильного формата.
        char16_t nxt = 0;
        for (int i = start +2; i < start+6; ++i) {
          int cur = 0;
          char &chr = encoded[i];
          if ('0' <= chr && chr <= '9') cur = chr - '0';
          if ('a' <= chr && chr <= 'f') cur = chr - 'a' + 10;
          if ('A' <= chr && chr <= 'F') cur = chr - 'A' + 10;
          nxt = (nxt << 4) + cur;
        }
        result += nxt;
      }
      return result;
    }
    Ответ написан
  • Как можно улучшить код?

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


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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Очень многие числа нельзя записать в виде числа с плавающей запятой, потому что они не представимы в виде доичной дроби с заданным количеством знаков. Например вы 1/3 как десятичную дробь не запишите. Ибо там 0.3333... - бесконечная последовательность троек. Для хранения double выделенно сколько-то бит под мантиссу, но их сильно меньше бесконечности.
    Поэтому ни 1/10, ни 3/100, ни 1467/1000 и почти любая дробь будет непредставима в виде float. Поэтому, если вам нужна точность, то вы округляете до целого и храните количество, скажем, тысячных долей в целых числах. Как сумму денег вы храните не долларах, округленных до 2 знаков, а как целое число центов.
    Ответ написан
    Комментировать
  • В чем проблема в коде работы с графом?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Ошибка в том, что у вас граф криво задан. У вас там ровно 6 списков. А размер графа - 7. Поэтому в MakeStep вы обращаетесь к graph[6], а это undefined behavior. А там непонятно, что происходит. Может вы таблицу портите каким-то значениями и никогда положительного значения не получаете. Скорее всего корраптите память через обращение к мусорным adj в std::array (который на стеке лежит) и получаете мусор в каких-то локальных переменных.
    Ответ написан
  • Компиляция C++ кода на Ubuntu и Windows даёт мне разный результат, почему?

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

    Советую переписать код. Возвращайте std::array<std::bitset<16>,4> например. Вместо push_back сразу обращайтесь к i-ому элементу ответа.

    Далее, у вас там 2 функции делают одно и то же - разбивают большой bitset на несколько маленьких. Напишите template функцию, которая выделяет из битсета длиной N битсет длиной M со сдвигом offset. Внутри просто циклом присваивайте res[i] = input[i+offset].

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

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

    Т.е. действительно, в вашем случае надо в AIJH добавить точки ABKJH.

    Образуются ребра длины 0 - значит повторяющиеся вершины надо просто выкинуть.
    Ответ написан
    Комментировать
  • Как решить данную задачу на двумерные массивы c++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    int sum = 0;
    int cnt = 0;
    for (int dx = -1; dx <= 1; ++dx) {
      for (int dy = -1; dy <= 1; ++dy) {
        if (dx == 0 && dy == 0) continue;
        int nx = i + dx;
        int ny = j + dy;
        if (nx < 0 || nx >= N || ny < 0 || ny >= M) continue;
        sum += A[nx][ny];
        ++cnt;
      }
    }
    B[i][j] = cnt == 0 ? 0 : sum / cnt;
    Ответ написан
    Комментировать
  • Что не так с кодом, проверяющим логическую схему?

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

    Во-вторых, у вас ошибка с тем, что вы из bitmask берете биты, которые есть числа 0 и 1 и проводите над ними битовые операции, а не логические. И это у вас там 32-битные числа же! Для | и & оно еще совпадает с вашими ожиданиями, а вот ~ обращает ВСЕ 32 бита числа.

    Поэтому ~(bitset[E] | bOrD) всегда выдаст или -1 или -2. Вы потом это пропустите через or, получите опять же -1 или -2 и в конце преобразуете это в bool. И вот тут-то оно всегда и станет true.

    Чтобы это исправить, или используйте логические операции (||, &&, !), или вместо ~x используйте x^1, или в самом конце возвращайте результат с &1, чтобы значения остальных бит ни на что не влияли.
    Ответ написан
    5 комментариев
  • Правильно ли понимаю работу ссылок в С++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Это называется передача по ссылке/передача по значению. С амперсантом, передается ссылка на переменную. Иначе - копия значения переменной. Если вы будете менять копию значения, ничего вне функции не изменится, ведь вы копию меняете. А если будете менять значение ссылки, вы будете менять значение той же самой переменной.
    Ответ написан
    Комментировать
  • Объясните как посчитать график отношений RoR?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Судя по всему, у вам надо поставить звездочки в клетках i,j, если R[i][j] или если существует k, т.ч. R[i][k] и R[k][j].

    Видимо, "RoR" означает "связаны R напрямую или через одного". Я уж и не помню, как эта операция называется математически.

    Решение в лоб: завдеите массив для графика ответа и вычисляйте каждое значение поотдельности. Во-первых, если есть отношение во входном R в этой же ячейке. Во-вторых, напишите третий вложенный цикл, который переберет все промежуточные элементы, и установите ответ в true (или звездочку там поставьте), если оно есть хотя бы в одном R[i][k] и R[k][j] одновременно.
    Ответ написан
    5 комментариев
  • Почему нельзя использовать std::function как аргумет шаблонной функции?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Потому что лямбда не ялвяется std::function. Компилятор, вообще говоря, может лямбду привести к типу std::function, но не в вашем случае. Вам надо, например, самим преобразовать лямбду в std::function:
    std::function<bool(int, int)> comp = [](int left, int right)
      {
        return left < right;
      };
      Sort(vec, comp);


    Сам компилятор тут это сделать не может, потому что ему тип к которму приводить-то неизвестен - он зависит от параметра шаблона T.

    Можно, еще, например, указать компилятору параметры шаблона, тогда все скомпилируется:
    Sort<int>(vec, [](int left, int right)
      {
        return left < right;
      });


    Но лучший вариант - не использовать std::function в шаблоне. Просто используйте какой-то typename U, у которого вы продполагаете существует operator(int, int). Если туда передать не function и не лябмду, оно не скомпилится:

    template <typename T, typename U>
    void Sort(std::vector<T>& vector, U comparison) {
        // Используете comparison, как-будто это std::function:
        if (comparison(1, 1)) return;
    };
    
    
    int main()
    {
      std::vector<int> vec = { 1, 2, 3, 4, 5, 7, 6, 9 ,8 };
    
      Sort(vec, [](int left, int right) -> bool
      {
        return left < right;
      });
        return 0;
    }
    Ответ написан
    Комментировать
  • Почему умножение матрицы 8x8 медленнее чем 10x10?

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

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

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

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

    Вот дружественные функции там есть, да.

    И в вашем коде компилятор видит, что есть какая-то функция TakeApple в namespace Human. Метод класса Human он тут не замечает вообще. Ну и там, понятное дело, нет никакого доступа к приватным членам класса Apple.

    Вам надо или помечать дружественным весь класс Human, или выносить ваш код в отдельную функцию, которая будет дружественная обоим классам.
    Ответ написан
    3 комментария
  • Как решить задание без использования правила Лопиталя?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Раскройте sin(6x) по формуле синуса двойного и потом тройного углов. В итоге 2sinx - 1 и в числителе и в знаменателе сократится.
    Ответ написан
  • Возникает ошибка, но не знаю какая?

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

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

    Рекурсивная функция получает, например, сколько первых типов монет можно использовать и какую сумму надо набрать. Возвращает список монет. Внутри надо перебрать сколько раз последняя сонета береться: от 0 до 2 раз. Оставшаяся сумма рекурсивно собирается оставшимеся монетами (минус один к количеству типов, ведь последний мы уже использовали). Если рекурсивная функция что-то собрала, добавляем к ее ответу 0-2 теущие монеты и вощвращаем.

    Это отработает за 3^15*15 = 215233605 операций. Обычно это проходит. Можно соптимизировать: не брать текущую монету, если она слишком большая, останавливать перебор, если сумма первых монет недостаточна. Ну, или соптимизировать до 2^15*15: подсчитайте все возможные суммы, если можно брать по 1 монете. Таким же перебором или вообще циклом с битовой маской. Отсортируйте список из 32 тысяч чисел и проверьте, а есть ли там 2 числа, дающие искомую сумму (двумя указателями: двинули один раз левый, двигаем правый пока сумма слишком большая).

    Отдельно надо проверить, надо ли выводить -1 в ответ (сумма всех монет меньше N).
    Ответ написан
    Комментировать