Ответы пользователя по тегу Математика
  • Как графически показать эквивалентность двух множеств?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Наверно, на графике XY нарисовать обе функйции зависимости. Отметить отрезки допустимых x на OX, вертикальными линиями соединить концы отрезков с функцией зависимости, от точек пересечения горизонтальными линиями получить отрезок значений на оси OY. Если множества на оси OY совпали, то они эквивалентны (Спойлер: тут они не совпали. Например, инфинумом первого множества является 1, а второго - 27).
    Ответ написан
  • Почему любую булеву функцию можно представить в виде СДНФ или СКНФ?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Потому что эти формы - это тупо перечисление всех наборов входных значений, которые дают истину, или ложь (в другой форме). В СДНФ вы получаете слагаемые, объедененные через ИЛИ. Каждое слагаемое через И задает все переменные так, что только вот в конкретном наборе входных данных это слагаемое будет истинно. Раз они все через ИЛИ соединены, то вся функция истинна только если входные значение из нужного набора. Аналогично СКНФ - но там каждая скобочка истина, если входные переменные не равны набору, на котором функция должна давать ложь.
    Ответ написан
    Комментировать
  • Почему вектор перемещения не поддается правилу треугольника при вычитании векторов?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    На графике или в тексте ошибка. Или там r-r0 должно быть в тексте, или стрелочку не в ту сторону нарисовали.
    Так бывает - в учебниках и методичках встречаются опечатки.
    Ответ написан
    Комментировать
  • Алгоритм для преобразование матрицы в треугольную?

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

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

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

    Сходу очевидно, что x=y=a+b=c+d+k дает по нулям все левые части, что удовлетворяем всем неравенствам.

    Так что, берем x=y=a=c=1, b=d=k=0

    Плюс, можно менять 1 на что угодно. Можно распределять эту 1 между a и b, а так же между c, d и k. Бесконечно много решений.

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

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

    Совет: обозначте за x длину диагонали от точки пересечения к углу короткого основания. За y обозначьте оставшейся кусок диагонали (к большему основанию). У вас там 4 прямоугольных треугольнка образуются со сторнами xx, xy, yx, yy. Сумма их площадей - 110. Диагональ треугольника xx тоже дана (это короткое основание - 4). Искомое оснавание - диагональ треугольника yy (по теореме пифагора получается sqrt(2)*y).

    Составьте 2 уравнения, решите их, формулу запрограммируйте.
    Ответ написан
    Комментировать
  • Как подступиться? Нужна ли равномерная сетка ВЫЧМАТ?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Да, можно воспользоваться этой оценкой. Что там за Mn я, правда, не знаю. Эту часть надо вычислять имея явный вид функции f(x)=e^x.
    Ответ написан
    Комментировать
  • Как правильно умножать восьмичные числа с плавающей точкой?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    В столбик. Точно так же как обычные десятичные числа, только помните, что цифры 8 нет. Если получилось больше 7, все остальное, поделенное на 8 переносится дальше.
    Ответ написан
    Комментировать
  • Теоретически, что будет если дать процессору инструкцию поделить на ноль без механизмов обработки?

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

    Можно было бы предположить, что оно повиснет, как при делении на 0 на механическом калькуляторе. Хоть это и прикольно выглядит.

    Но процессор не вычитает кучу раз подряд, ведь там двоичная система счисления. Разряд вычисляется проверкой на переполнение при одном вычитании со сдвигом, а результат идет дальше. Вот лекция о том, как устроена схема делителя.

    При вычитании нуля со сдвигом там никогда переполнения быть не будет, поэтому все биты ответа получатся равными 1.

    В итоге оно скорее всего выдаст неправильный результат. Что-то вроде 2^31-1 для любого делимого.

    Правда, если Intel/Amd/etc. нагородили каких-то оптимизаций или как-то усложнили схему, то результат может быть другим.
    Ответ написан
    Комментировать
  • По какому алгоритму находить наибольшую общую подпоследовательность двух дублирующихся слов?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Вообще, вот алгоритм для произвольных слов: https://e-maxx.ru/algo/longest_increasing_subseq_log

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

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

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Есть еще вот такое решение. Выводится так: задаем обе прямые параметрически (точка + t или u, помноженная на вектор вдоль прямой). Получаем выражение для квадрата расстояния между точками как функцию от t и u. Ищем ее минимум, приравняв к 0 частичные производные. Там получаются 2 линейных уравнения.

    Vector3 a = axis2.first - axis1.first;
    Vector3 v1 = axis1.second - axis1.first;
    Vector3 v2 = axis2.second - axis2.first;
    float v11 = Vector3::DotProduct(v1, v1);
    float v12 = Vector3::DotProduct(v1, v2);
    float v22 = Vector3::DotProduct(v2, v2);
    float av1 = Vector3::DotProduct(a, v1);
    float av2 = Vector3::DotProduct(a, v2);
    // Решаем систему методом Крамера:
    // t*v11-u*v12=av1
    // t*v12-u*v22=av2
    float d1 = -av1*v22+v12*av2;
    float d2 = v11*av2-v22*av1;
    float d = -v11*v22+v12*v12;
    float t = d1/d;
    float u = d2/d;
    point1 = axis1.first + v1 * t;
    point2 = axis2.first + v2 * u;
    Ответ написан
    Комментировать
  • Что делать, когда Wolfram говорит, что будет корень, а считать не хочет - a³+b³=z³?

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

    Точнее всех будет считать python если использовать библиотеку Decimal:
    from decimal import *
    getcontext().prec = 400
    a = Decimal('112312312312312311231231231231231123123123123123112312312312312311231231231231231123123123123123');
    print(pow(a,Decimal(1/3.0)))


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

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

    Если у вас всего 4 пикселя, то возможно x и y - это будут 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 Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Из отрезков заданной длины можно составить многоугольник тогда и только тогда, когда максимальный строго меньше суммы всех остальных. Или, тоже самое: максимальный строго меньше половины суммы всех.

    Код проверки будет примерно такой:
    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 Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Можно составить многугольник из отрезков, тогда и только тогда, когда максимальный короче суммы всех остальных. Ну или, максимальный меньше половины суммы всех. Множитель 2 у вас там лишний.

    Доказательство элементарно: В противном случае, очевидно, всех остальных сторон не хватит составить путь от двух точек длиннейшего отрезка.
    А дальше возьмем окружность у которой этот длиннейший отрезко будет хордой. Приложим все остальные отрезки как хорды подряд. Если их не хватает замкнуть многоугольник, то уменьшим радиус. Если они закрывают суммарно дугу окружности больше, чем между хордой на самом длинном отрезке, то увеличиваем радиус. По какой-нибудь теореме о нуле непрерывной функции где-то существует радиус, для которого все эти отрезки оформятся в выпуклый мноугольник, вписанные в окружность.
    Ответ написан
    Комментировать
  • Можно ли быстрее чем за 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: прилизал код немного.
    Ответ написан
    Комментировать
  • Как правильно задать интервал для формулы a³+b³=c³+1?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Вы ищите a и b из одного и того же интервала. Но, как вы сами видите, могут быть решения, где разные переменные из разных интервалов. Поэтому один интервал на 1-2000 находит больше решений, чем два интервала 1-1000 и 1001-2000.

    Я думаю, вам стоит вообще внешний цикл убрать и всегда работать только с одним интервалом.

    Можно чуть чуть ускорить решение, если не увеличивать c в цикле, а вычислить его по формуле (an+bn-1)^(1/n). Какая-нибудь функция pow вам поможет. Она даст неуелое число, его надо округлить и проверить, что равенство ввполняется.

    Еще, ваша проблема, что c у вас может быть не из заданного интервала. Надо или жто проверять, или перебирать b и c, считать a, вместо перебора a, b и вычисления c. Потому что a < c. И раз c перебирается в интервале - то и a будет в нем.
    Ответ написан
    44 комментария
  • Как определить есть ли противоречия в цепочке логических выражений?

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

    Все неравенства "==" замените на пару "<=" и ">=".
    Добавьте неравенства 1 < 2, 3 < 4 и т.д. для каждой пары соседних на числовой прямой чисел во входных данных

    Постройте граф: Каждой переменной и уникальному числу во входных данных сопоставьте одну вершину. Проведите для каждого неравнества ребро от меньшей вершины к большей, раскрашенное в 2 цвета: черный, если неравнество нестрогое (<=), белый - иначе.

    Теперь, если в этом графе нет циклов, содержащих белые ребра (строгие неравенства) - то противоречий нет: Все циклы целиком из черных ребер означают, что все вершины имеют одинаковое значение. Можно эти вершины все объединить в одну новую. Раз белые ребра (<) циклов не образуют, то получившийся граф будет ациклическим и можно назначить всем вершинам какие-то числовые значения, удовлетворяющие условиям. Проблема может еще быть, что нет целых решений вроде 1== a < b < c == 2, но это можно потом проверить в топологической сортировке жадно назначая всем вершинам числа. Или противоречия вида 2==3. Тоже решается после получения компонент связности.

    Итак, алгоритм: найдите в этом графе компоненты сильной связности. Потом проверьте все ребра. Если белое ребро (строгое неравнество) имеет оба конца в одной и той же компоненте - вы нашли противоречие.

    Теперь надо постараться назначить кадой компоненте числовое значение так, чтобы не было противоречий. Это можно делать жадно, назначая каждой компоненте минимально возможное значение.

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

    В конце вы получите для каждой компоненты ее численное значение без каких-либо противоречий.
    Ответ написан
    4 комментария