Задать вопрос
  • В чем причина данной ошибки?

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


    У вас 2 раза определен class парсер::ВыражениеParser.

    Компилятор даже указал на оба определения: они оба в файле ВыражениеParser.h, но включенного 2 раза из разных исходников:
    In file included from ВыражениеVisitor.h:8,
                     from ВыражениеParser.cpp:6:
    ВыражениеParser.h:15:8: ошибка: повторное определение «class парсер::ВыражениеParser»
    ...
    In file included from ВыражениеListener.h:8:
    ВыражениеParser.h:13:8: замечание: предыдущее определение «class парсер::ВыражениеParser»


    Пока похоже, что вы там намудрили с include-guard'ами из-за чего один и тот же хедер включается несколько раз. Выкладывайте начало файла ВыражениеParser.h.
    Ответ написан
  • Как сделать преобразование фурье для изображения по xy?

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

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

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

    А так, скорее всего вам подойдет функция memset. Какими-нибудь нулями все заполнить - отлично можно. Хоть там int, хоть char, хоть float.
    Ответ написан
  • Как вывести буквы, которые используется наиболее кол-во раз?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Задача разбивается на 2: 1) подсчитать для каждой буквы количество ее вхождений, 2) Найти максимум и вывести его индекс.

    Первая задача решается просто - заведите массив счетчиков. Например, на 256 элементов. Для каждой буквы строки увеличивайте счетчик с индексом равным символу (помните, же, что char в C++ - это целочисленный тип?)

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

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Если не обязательно делать поворт на месте, то вся суть алгоритма вот в этой одной строке:
    result[i][j] = arr[n-1-j][i];
    Надо только циклы прогнать по нужным границам, да массив нужного размера создать.

    Если матрица квадратная, то элементы сдвигаются по кругу в четверках - и это можно сделать без дополнительного массива . Можно делать сдвиг по кругу со временной переменной. Что-то вроде этого:
    tmp = arr[i][j];
    arr[i][j] = arr[n-1-j][i];
    arr[n-1-j][i] = arr[n-1-i][n-1-j];
    arr[n-1-i][n-1-j] = arr[j][n-1-i];
    arr[j][n-1-i] = tmp;


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

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

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

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Точка на окружности радиуса r, с центром x0, y0, под углом alpha к горизонтальной оси имеет координаты:
    x = x0 + r*cos(alpha)
    y = y0 + r*sin(alpha)


    У вас есть 2 окружности - внешняя, и невидимая внутренняя. Тикмарки - это куски радиуса между ними. По формуле выше (с двумя разными радиусами) вы можете найти 2 точки конца каждого отрезка.
    Ответ написан
    22 комментария
  • Почему -Wconversion разрешает передачу integer literal в char параметр?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Ну вообще, char - integral type. Поэтому передавать туда числовую константу можно - это никакой не варнинг. Компилятор сам понимает, что она должна быть типа char и даже проверяет на переполнение и выдает warning, если что.
    Ответ написан
    2 комментария
  • Как найти минимальное число прохождений по автомату до конечного состояния с N вероятностью?

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

    А вопрос из задачи (если его понимать как: минимальное количество шагов, чтобы хотя бы раз посетить конечную вершину с вероятностью >99%) становится эквивалентен: минимальное количество шагов, чтобы быть в конечной вершине с вероятностью не меньше 99%.

    А тут уже надо найти минимальное число k, такое что соответствующее значение в матрице A^k было бы > 0.99. A тут - это матрица переходов.

    Можно или в тупую умножать матрицу саму на себя, пока значение в строке начальной вершины и столбце конечной вершины не станет достаточно большим. Это будет O(N^3*ответ). Или можно делать хитро: бинарным поиском перебирайте степень, а внутри логарифмическим возведением в степень считайте A^k. Это будет O(N^3*log(ответ)^2).
    Ответ написан
    Комментировать
  • Как написать функцию sin из библиотеки math.h в Си?

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

    Ваша функция, как и стандартная, работает с радианами и выдает такой же результат от того же аргумента Pi*30/180=Pi/6.

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

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

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

    Вот у вас есть гипотеза m=(l+r)/2 - вы хотите проверить, а как она соотносится с длинной круга. Допустим, вы уже прошли x метров и прошли k полных кругов. Уже только из этой информации можно оценить, какая длина круга может быть. Во-первых, убедитесь, сравните floor(x/m) и k. Если floor(x/m) > k вы уже знаете, что длина круга больше m, ведь для круга длины m и более коротких значений вы бы насчитали floor(x/m) или больше оборотов. Если floor(x/m) < k, то уже очевидно, что длина круга меньше m. Если же floor(x/m) = k, то спросите run m-x%m - сколько осталось пройти до финиша, если бы длина круга была равна m. Если вы получили в ответ 1, то значит круг не длинее m. В протвином случае круг строго длиннее m.
    Ответ написан
    4 комментария
  • Посчитать многоугольник почему не работает програма?

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

    Код проверки будет примерно такой:
    def can_construct_polygon(lengths):
      return len(lengths)>0 and max(lengths) < sum(lengths)/2


    В списке lengths надо передать длины всех отрезков. Если у вас там вектора на плоскости заданы в vectors, то через map подсчитайте их длины сначала.

    Edit:

    Раз поворачивать вектора-отрезки нельзя, то действительно, составить многоугольник можно, если по-координатная сумма векторов дает (0, 0).

    Все еще остается вопрос, а допускаются ли вырожденные мноугольники? Например, можно ли составить такой из веторов (1,0), (-1,0). Если допускаются, то проверять длины не надо. Если нет, то все еще надо, как я выше указал, сравнить максимальную длину с суммой всех длин.

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

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    (Отредактировал ответ согласно комментариям). Как выяснилось, в задаче длины вот групп одинаковых цифр могут достигать 10^18. Поэтому попытка развернуть эту запись обречена на провал: все эти цифры потребуют миллионов террабайт. Естественно, ваша программа падает еще на этапе ввода ( а еще, вы там читаете int, в который такие большие числа не влезают, что будет дополнительной ошибкой).

    Надо прочитать группы для каждого числа, развернуть эти списки, и складывать группу с группой. Будет у вас 2 указателя, как при слиянии двух массивов. Если первые группы в двух числах разной длины, то откусывайте от большей группы длину равную меньшей. Записывайте в ответ сумму групп, сдвигайте указатель в одном массиве, а во втором укоротите первую группу.

    Главная часть решения - это научиться складывать две группы цифр равной длины (плюс перенос). Вроде 7777 + 4444 +1 = 12222 - 4 двойки и 1 единица (помните, порядок у нас развернутый же). Тут можно всегда выделять в отдельную группу первую цифру из-за переноса. Отдельный случай будет, похоже, если цифры дают в сумме 9 и есть перенос (10000..000). А иначе вы получите что-то вида abbbbbbc в оставшихся цифрах. Главное, что при сумме нельзя группы распаковывать.

    В конце разверните группы и объедините подряд идущие группы для одинаковых цифр.
    Ответ написан
  • Как проверить многоугольник на закольцованность?

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

    Доказательство элементарно: В противном случае, очевидно, всех остальных сторон не хватит составить путь от двух точек длиннейшего отрезка.
    А дальше возьмем окружность у которой этот длиннейший отрезко будет хордой. Приложим все остальные отрезки как хорды подряд. Если их не хватает замкнуть многоугольник, то уменьшим радиус. Если они закрывают суммарно дугу окружности больше, чем между хордой на самом длинном отрезке, то увеличиваем радиус. По какой-нибудь теореме о нуле непрерывной функции где-то существует радиус, для которого все эти отрезки оформятся в выпуклый мноугольник, вписанные в окружность.
    Ответ написан
    Комментировать
  • Почему в коде вызывается конструктор с initializer_list, а не с intами?

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

    Если вы хотите вызвать конструктор с числами, то вызывайте, внезапно, конструктор с числами:
    Any n(1, 15);
    Ответ написан
  • В чем разница 2ух кодов?

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

    Попробуйте ввести эти же 2 длинных числа, но поменять их местами, чтобы первое было коротким. Все работает?

    Сразу вижу 2 проблемы, вообще не обрабатывается случай num1.size() <= num2.size(). Во-вторых, в конце, где вы нормализуете число, если там окажется 11, где-то, то вы оставите в этом разряде 0, а не 1, как надо. Правда, при сумме двух чисел там 11 получится за длиной максимального числа не может появиться, ибо туда может прийти только +1 от переноса. Но код все-равно логически неверен.
    Ответ написан
    Комментировать
  • Можно ли быстрее чем за O(N) подсчитать сумму S(N,K,M) = sum i=0..N K*i%M?

    wataru
    @wataru Автор вопроса, куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Совершенно случайно наткнулся вот на это вот равнество: hermite's identity (в твитте с прикольным доказательством. Зацените).

    C помощью него наконец-то вывел способ подсчитать эти суммы за O(log n)! Я знал, что это можно сделать!

    Итак, во-первых, можно переключатся между суммами floor(i*k/m) и (i*k)%m через вот это равенство: floor(i*k/m) = (i*k - (i*k)%m) / m
    Это нам позже поможет. В сумме через floor можно сократить GCD(m, k) в них. В сумме через модуль можно сделать k %= m, если оно больше m, да и сократить полные "обороты" в n.

    Итак, можно допустить, что m > k, m >n, GCD(m, k) = 1, иначе преобразуем сумму к нужной форме и все упростим.

    Дальше, применим равенство hermite's, взяв x = i/m, n = k.

    Потом поменяем местами суммы. Под знаками суммы будет floor(i/m + t/k) (где t - новая переменная суммирования от 0 до k-1). Присмотритесь к этому выражению - там 2 числа меньших 1. Т.е. весь этот floor даст 1, только если t/k >= 1-i/m. Отсюда можно решить это неравнество, сдвинуть нижнюю границу суммирования и получить сумму единиц во внутренней сумме. Заменив ее всю на количество слагаемых там вылезает floor (t*m/k). Т.е. мы выразили сумму i*k/m через сумму t*m/k. Но мы же помним, что можно перейти к сумме модулей и там сократить множитель k в числителе. Таким образом мы вычисляем сумму для (m, k) через сумму для (k, m%k). Это точно такой же переход, как и в GCD, поэтому суммарно будет всего O(log n) итераций. Вообще, выкладки довольно нудные, ибо сумма для t*m/k будет не от 0 до какого-то n', а от n' до k-1. Но можно взять известное значение для суммы полного оборота (от 0 до k-1) и из нее вычесть сумму от 0 до n'-1. Эта сумма известна, потому что при GCD=1, она пройдется по всем остаткам в каком-то порядке.

    Формула примерно такая получается:
    FloorSum(n, k, m) = (m-1)*(k-1)/2 - (n1+1)*n1*(m/k)/2 + (n - m + 1)*(k-n1-1) - FloorSum(n1, m%k, k)
    n' = floor(((m-n)*k-1)/m)


    Вот код. Значения совпадают с тупым решением для всех чисел до 1000 и для миллиардов случайных чисел до миллиона.
    // sum i = 0.. n floor(i * k / m)
    // GCD(k, m) must be 1.
    // n < m
    // k < m
    long long FloorSumInternal(long long n, long long k, long long m) {
    	if (k == 0 || n <= 0) return 0;
    	if (m == 1) return k*n*(n+1)/2;
    	const long long n1 = ((m-n)*k - 1)/m;
    	long long ans = (m-1)*(k-1)/2 - (n1+1)*n1*(m/k)/2 + (n - m + 1)*(k-n1-1);
    	ans -=  FloorSumInternal(n1, m%k, k);
    	return ans;
    }
    
    
    // sum i = 0.. n floor(i * k / m)
    long long FloorSum(long long n, long long k, long long m) {
    	if (k == 0 || n <= 0) return 0;
    	if (m == 1) return k*n*(n+1)/2;
    
    	const long long d = Gcd(m, k);
    	m /= d;
    	k /= d;
    	if (k >= m || n >= m) {
    		// (n*k*(n+1)/2 - ModSum(n, k, m, d))/m;
    
    		const long long nn = (n+1)%m-1;
    		const long long num_full = (n+1) / m;
    		const long long kk = k % m;
    
    		long long ans = 0;
    		ans = (k*n*(n+1) - kk*(nn+1)*nn)/m - num_full * (m-1);
    		ans /= 2;
    		ans +=  FloorSumInternal(nn, kk, m);
    		return ans;
    	}
    	return FloorSumInternal(n, k, m);
    }
    
    
    
    // sum i = 0.. n (i * k) % m;
    long long ModSum(long long n, long long k, long long m)
    {
    	long long d = Gcd(k, m);
    	if (k == 0 || m == 1) return 0;
    	// (i*k) % m = i*k-floor(i*k/m)*m
    	k %= m;
    	long long num_full = (n+1) / m;
    	long long ans = num_full * (m-d) * m/2;
    	n = (n+1)%m-1;
    	if (n > 0) {
    		ans += ((long long) k)*(n+1)*n/2 - m*FloorSum(n, k/d, m/d);
    	}
    	return ans;
    }


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

    Edit: прилизал код немного.
    Ответ написан
    Комментировать
  • Как получается формула N*(N-1) / 2?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Ну вы подставьте в формулу число. Допустим, N=3: 1+2+3 = 6. N(N-1)/2= 3*2/2 = 3. Не сходится!
    Правильная формула, все-таки N(N+1)/2.

    А разница в том, что в учебнике получается сумма от 1 до N-1. Т.е. в формулу прогрессии от 1 до N надо подставить N-1. Вот и получается (N-1)(N-1+1)/2 = (N-1)N/2
    Ответ написан
    1 комментарий
  • Как быстро умножают края матриц?

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

    Или можно наивно последние 1-7 слагаемых в каждой сумме подсчитать. Это займет O(n^2), что по сравнению с остальным алгоритмом - копейки.
    Ответ написан
    2 комментария
  • Как убрать time.sleep() или чем его заменить а автотестах?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Все индивидуально. Чего этот sleep в коде ждет?
    Может, тут он ждет отклика от сервера, и там действительно надо 200мс ждать. И просто заменой time sleep на что-то вы ничего не исправите. Или это анимация чего-то на экране, и тут можно в 0 все убирать.

    Но вообще гуглите simulated time python.
    Посмотрите, может simpy вам тут поможет.
    Ответ написан
    1 комментарий