Ответы пользователя по тегу Математика
  • Посчитать многоугольник почему не работает програма?

    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 комментария
  • Какое решение уравнения x^3 + y^3 = z^3 в дробных числах?

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

    А в иррациональных - берете вообще любые x, y и по ним считаете z. Все.
    Например, x=10, y=1, z= 1001^(1/3)
    Или x = 20^(1/3), y= 7^(1/3), z=3
    Их континуум этих решений (бесконечно много).
    Ответ написан
    24 комментария
  • Есть ли у этого название?

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

    Подозреваю, что вам нужно целое число, помещающееся в делимом (семь двоек в 15). Тогда такая операция называется "деление нацело". Она вместе с делением по модулю идет парочкой: вот это деление нацело дает количество целых кусков, а деление по модулю (оно же "взятие остатка") дает сколько там остается.
    Ответ написан
    Комментировать
  • Как классифицировать числовой ряд?

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

    Все-таки все эти методы кластеризации разработаны для более общего случая. А у вас тут данные одномерные и численные уже - так что все совсем просто.

    Во-первых, данные надо отсортировать, если уже не. А дальше у вас тут 2 переменные - (i,j) - первый и последний элемент в средней группе.i>0,j<n-1.

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

    Но вообще можно, наверно, просто взять 2 максимальных промежутка между соседними числами и по ним разделить. В примере выше этот метод отлично разбивает на 3 группы: 1-103, 999-1001, 9000-9500

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

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

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

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Ну, скалярное произведение вектора самого на себя - даст квадрат его длины по определению (|a|*|a|*cos(0)). Если менять точки - меняется длина вектора - меняется скалярное произведение.
    Ответ написан
    Комментировать
  • Доказать рекуррентную формулу. Кто может решить? Что с этим вообще можно сделать?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    В задаче опечатка, там где-то должно быть J(n-2) вместо J(n-1), и в коэффициентах я не уверен.

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

    Осталось поэксперементировать перебирая разные части x^n и корня из квадртатного выражения: что из них интегрировать, а что дифференцировать.

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

    Еще можно с конца идти - перенесите все интегралы в одну сторону, сгрупируйте. Получите интеграл равен функции. Можно проверить равенство просто продифференцировав функцию.

    Похоже в задании опечатка - там должны быть J(n-1) и J(n-2), потому что дифференцируя вот эту свободную штуку получается (C1x^n+C2x^(n-1) + C3x^(n-2)) / sqrt(ax^2+bx+c). Значит, с другой стороны должны быть линейная комбинация J(n), J(n-1) и J(n-2).
    Ответ написан
    Комментировать
  • Как позиция объекта соответствует четырёхмерной матрице?

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

    Четвертая координата позволяет записывать одной матрицей повороты/растяжения и сдвиги. Если у вас матрица 3x3 (не "трехмерная" - у нее все так же есть только ширина и высота), то точка (0, 0, 0) всегда останется (0, 0, 0). Ведь на что 0 не домножай - останется 0. Поэтому матрицами 3x3 можно записать только повороты и сжатия, но не сдвиги.

    Поэтому вводят фиктивное четвертое измерение w. При этом удобно считать, что координаты точки (x, y, z, w) - Это (x/w, y/w, z/w). Это еще иногда называют однородными координатами. Еще один плюс этого объекта в том, что им можно описать точки на бесконечности (когда w = 0).

    Вот тут уже можно составить линейное преобразование (т.е. взять матрицу), которое оставляет w нетронутым, но использует его для сдвига:
    x' = a11*x + a12*y + a13*z + a14*w
    ...
    w' = w

    Вот в a14 - как раз и находится сдвиг по оси X.
    Ответ написан
    3 комментария
  • Можно ли бесконечное число планет выпрямить в бесконечную плоскость?

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

    Количество планет - счетное (Можно по спирали их все занумеровать).
    Каждая планета в форме блина - континуум ("количество" точек в плоскости или в круге, или на отрезке).

    Счетное количество континуумов - тоже котнинуум по мощности.
    Плоскость - тоже континуум.

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

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Знаете 2 точки дуги - знаете длину хорды. Дальше надо на листке нарисовать окружность, хорду и серидинный перпендикуляр. Нарисовать несколько прямоугольных треугольников и найти длину куска от центра хорды до искомой середины. Пусть центр O, исходные точки A,B а искомая точка - M. Середина хорды С. OM = R. OС^2+CB^2=R^2, CM = OM-OC.

    Итого - длина искомого куска CM = R - sqrt(R^2-|AB|^2/4)

    Для нахождения координат M надо взять середину отрезка AB и отложить от нее перпендикулярный AB вектор длины по формуле выше.
    Ответ написан
    Комментировать
  • Почему функция y=x^x начинает возрастать, начиная с аргумента 1/e?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    В смысле почему? Почему y=x^2 имеет минимум в 0, почему синус имеет период в 2 пи? Ну вот просто такое свойство у данной функции. Так получилось. Это свойство можно вывести, например, посчитав производную заданной функции.

    Хочется какую-то интуицию? При маленьких x вы маленькое число возводите в маленькую степень при увеличении x вы увеличиваете и основание и степень. Увеличивая основание, вы увеличиваете результат. Ведь если большее число возвести в ту же степень, то результат увеличится. С другой стороны, основание-то меньше 1. Если увеличивать степень, то вы больше домножаете на маленькое число и результат должен уменьшатся. Для каких-то чисел основание перевешивает степень и результат при изменении x увеличивается. Для каких-то - наоборот.
    Ответ написан
    Комментировать
  • Как составить диаграмму Эйлера и решить ее?

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

    Составьте уравнения. 4 куска в каддом круге суммируются к количеству преподавателей этого языка. 2 куска в каждой дольке из 2 кругов в сумме дают заданное число. Скмма всех 7 кусков - сколько всего преподов. 7 уравнений, 7 неизвестных. Решайте. Можно уравнения складывать и вычитать.
    Ответ написан
    8 комментариев
  • Как нарисовать кривую Лагранжа через полином?

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

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

    Квадрат - это все точки (X, Y), которые удовлетворяют неравенствам:
    x1 <= X <= x1 + w1
    y1 <= Y <= y1 + w1


    Пересечение двух квадратов - это точки, которые удовлетворяют одновременно каждой паре неравенств, т.е. удовлетворяют сразу четырем неравенствам:
    x1 <= X <= x1 + w1
    y1 <= Y <= y1 + w1
    x2 <= X <= x2 + w2
    y2 <= Y <= y2 + w2


    Тут уже видно, что фактически есть пара неравенств на X, и есть пара неравенств на Y. Они независимые. Вот и получается, что пересечение можно искать отдельно по каждой оси.

    Рассмотрим одну пару:
    x1 <= X <= x1 + w1
    x2 <= X <= x2 + w2


    Вообще, такие системы неравнеств решают в школе, классе этак в 7.

    Сконцентрируемся на левых границах. Что значит, что X >= x1 и X >= x2? Это значит, что X больше обоих чисел x1 и x2. Это можно записать одним неравнеством - X больше максимума из двух чисел:
    max(x1, x2) <= X

    Так же и по правым границам:
    X <= min(x1 + w1, x2 + w2)

    В итоге:
    max(x1, x2) <= X <= min(x1 + w1, x2 + w2)

    Эти неравенства имеют решение, если левая граница не превосходит правой:
    max(x1, x2) <= min(x1 + w1, x2 + w2)

    Вот у вас условие, что по оси OX есть хоть одна точка пересечения. Если вам касающиеся квадраты не надо считать пересекающимеся, то замените знак <= на строгое неравенство.

    Точно также проверьте, что есть пересечение по OY. Если пересечение есть и там и там, то квадраты пересекаются. Т.е. весь ваш код должен найти 2 минимума, 2 максимума, сделать 2 сравнения и соединить их через логичиское И.
    Ответ написан
    5 комментариев
  • Является ли множество рациональных чисел подмножеством рациональных чисел?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Да. По определению. "Подмножество" - это как меньше-равно для чисел. Поэтому еще выделяют определение "собственное подмножество". Это уже как "меньше". В этом определении само множество не включается.
    Ответ написан
    Комментировать
  • Как сделать чтобы число с каждым разом увеличивалось, до определенного значения, за определенное кол-во раз?

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

    exp_i= exp_1*k^i
    k=exp(( log(exp_n)-log(exp_1) )/(n-1))
    Ответ написан
    7 комментариев