|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Олимпиадные задачи по программированию.Системы счисления и арифметические задачи. Если вспомнить, что признаком деления на 9 в десятичной системе счисления является делимость на 9 суммы цифр числа действительно, пусть есть число S = a[n]*10n + a[n-1]*10(n-1) + ... + a[1]*10 + a[0]. А так как 10k - 1 делится на 9 нацело, то и S mod 9 = (a[n] + ... +a[1] +a[0]) mod 9, и т.д.), то аналогично получаем, что признаком деления на 15 в системе счисления с базисом 16 будет делимость на 15 суммы всех шестнадцатеричных цифр числа. [Назад] Разумеется, можно непосредственно вычислить это число в десятичной системе счисления, после чего разделить его на m, но в этом случае придется представлять число в виде (например) массива цифр и моделировать операции над этим числом. Существует другой простой алгоритм. a[n]*Kn + a[n-1]*K(n-1) + ... +a[0]*K0. Найдем остаток от деления его на m (остаток от деления a на b обозначим a mod b): (a[n]*Kn + a[n-1]*K(n-1) + ... +a[0]*K0) mod m = Это следует из следующих соображений: пусть Ki mod m=t, тогда Ki =p*m+t, и при этом для любых чисел b[i] выполняется Отметим также очевидное равенство Ki mod m =[(K(i-1) mod m) * K] mod m, Запись этого алгоритма (тут a[i] - K-ичные цифры числа): s:=0; t:=1; В переменной S после окончания работы алгоритма будет храниться искомый остаток. [Назад] Задача решается также, как и предыдущая: Алгоритм запишется следующим образом: В переменной остаток после выхода из цикла будет искомое значение. [Назад] Воспользуйтесь тем, что U[1] + U[1] = U[2], (1) Суммируем числа A и B поразрядно, используя приведенные выше правила, начиная со старших разрядов. После применения любого из правил опять начинаем просмотр числа со старших разрядов. 10 Первые два разряда просто сносятся, + 1001 затем применяем правило (2), + 01 и добавляем последние два разряда + 00 чисел A и B 11001 Для двух первых разрядов применяем правило (3) + 01 + 00 100001 + 01 Правило (1) + 00 100010 [Назад] Алгоритм следующий: cnt:=0; cnt - счетчик единиц в i. 100 = i and (i-1) [Назад] Пусть a(k) - k-ый член последовательности. Рассмотрим последовательность, формируемую по следующему правилу: a(0)=0; ряд a(0)...a(2k-1) получаем приписыванием к этой последовательности справа этой же последовательности, но при этом каждый член приписываемой части увеличивается на единицу. Получаем 0->01->0112->01121223->... Докажем, что a(k) есть сумма единиц в двоичном представлении числа k. Доказательство проведем по индукции. Для a(0)=0 это справедливо. Пусть предположение справедливо для всех a(i), 0<=i<=2(k-1)-1 (т.е. для всех чисел i, состоящих из не более чем k-1-го двоичных разрядов). Тогда в двоичном разложении числа l, 2(k-1)<=l<2k, в k-ом разряде появляется добавочная единица, и поэтому a(l)=1+a(l-2(k-1))), ч.т.д. Возьмем a(i) mod 3, и получим число, стоящее на i-ом месте в последовательности, описанной в условии задачи. Для того, чтобы найти a(i), необходимо, по доказанному, сосчитать количество единиц в двоичной записи числа i - см. задачу 5. [Назад] Будем менять местами содержимое переменных A и B. Существует несколько способов сделать это. 1.
Операция XOR над двумя переменными в машине реализуется как побитовая операция над двоичным представлением чисел. Поэтому, в частности, A XOR A = 0, A XOR B = B XOR A, A XOR 0 = A.
[Назад] Решение задачи 8. Если рассмотреть битовые представления числа A[i,j], помечающего точку (i,j) и чисел i и j, то обнаруживается, что A[i,j]=i XOR j, откуда получается, что A[i,j] XOR i=j, A[i,j] XOR j=i. Покажем, что A[i,j]=i XOR j. 1. Число A[i,j]=i XOR j не встречалось еще ни в строке i, ни в столбце j. От противного: существует такое j', что i XOR j = i XOR j' => i XOR j XOR i = i XOR j' XOR i => j'=j; 2. Пусть существует такое k<i XOR j, что k=i XOR L = j XOR M, и k еще не встречалось в строке i и столбце j (напомним, что по предположению все остальные уже заполненные элементы равны i XOR j, поэтому L>j и M>i). Тогда, так как M>i, то существует бит с номером t такой, что для любого R>t биты Mr и ir равны, t-ый бит Mt=1, it=0. Но так как j XOR M < j XOR i, то Jt=1. Так как L>j и L XOR i=j XOR M, то L = j XOR M XOR i. Рассмотрим i XOR M. В силу вышесказанного для любого бита с номером R, R>t, (i XOR M)r=0, а (i XOR M)t=1. При этом Jt=1, следовательно (i XOR j XOR M)r = Jr для r>t и то есть L<j ?! Противоречие. [Назад] Так как q<p, то цифры a и b должны лежать в пределах от 0 до q-1. Распишем A в системе с основанием p: A= ... = (ap+b)(p-2) + p-4 + ...) = { находим сумму бесконечно убывающей геометрической прогрессии со знаменателем p-2} = = Аналогично для A в системе с основанием q выполняется A= Получаем (bq+a)(p2-1)=(ap+b)(q2-1) Вычисляем выражения в квадратных скобках; обозначим их соответственно u и v: au=bv. Находим НОД(u,v)=s; обозначим r=u/s, f=v/s. [Назад] Очевидное решение: При попытке непосредственно вычислять координаты концов сегментов, принадлежащих множеству K[n], и определить, принадлежит ли a/b одному из этих сегментов даже для не слишком больших n за счет потери точности при вычислениях и из-за ограниченного числа знаков в машинном представлении чисел с плавающей точкой данный подход дает неверный ответ для большинства входных данных. При больших n вообще будет наблюдаться потеря значимости: число при делении на 3 станет таким малым, что в машине оно будет представляться нулем. Рассмотрим другой метод решения этой задачи. Так как мы постоянно должны делить сегменты на три части, то это наталкивает на мысль использовать троичную систему счисления и троичные дроби. В первой из удаленных интервалов (1/3,2/3) попадают только те точки x=0.a[1] a[2] a[3] ... в троичном разложении которых a[1]=1, кроме точки 1/3=0.1000... -правого конца сегмента [0,1/3]. Таким образом, в K [1] остаются все те точки, у которых a[1] <>1, либо a[1]=1, a[2] = a[3] = ...= = 0. Аналогично, в множестве K[i], i>=0, содержатся точки, у которых ни одно из чисел a[j], 1<=j<=i, не равно 1, а также точки, удовлетворяющие условию: a[j]=1, j - фиксировано, 1<=j<=i, a[l]<>1, l<j, и a[l] =0 для любого l>j (то есть, в записи троичной дроби только одна позиция равна 1, после нее все остальные позиции нулевые. Эти дроби соответствуют правым концам сегментов из множества K[i]). Запись алгоритма на Паскале имеет вид: x:=a; i:=1; [Назад]
Нас интересуют точки решетки (с целыми координата- * ми) в первом квадранте, попадающие внутрь круга * * * радиуса (n в степени 1/2). Интересующее нас * * * * множество (назовем его X) состоит из объедине- * * * * ния вертикальных столбцов убывающей высоты. * * * * * Идея решения состоит в том, чтобы "двигаться вдоль его границы", спускаясь по верхнему его краю, как по лестнице. Координаты движущейся точки обозначим Оценка числа действий очевидна: сначала мы движемся вверх не более чем на (n в степени 1/2) шагов, а затем вниз и вправо - в каждую сторону не более чем на (n в степени 1/2) шагов. [Назад] Число вида 2p-1 * (2p - 1), в двоичном представлении имеет р единиц и р-1 нулей. Максимальное значение р определяется как [(log2N)/2]+1. Затем проверяется является ли число совершенным для полученного значения p. Оно является совершенным, если для простого значения p, число 2p -1 является простым. Если получили несовершенное число, уменьшаем p на 1 и снова проверяем, является ли данное число простым. Совершенные числа получаются для значений р равных 2,3,5,7,13,17,19,31,61,89,107,127. [Назад] Запишем уравнение в виде sXeAk + pY = nYmAt + rX. Приравнивая коэффициенты при X,A и Y, получаем: X se=k Так как коэффициенты в формуле должны быть взаимно простыми, то следует найти НОД чисел k и t (Задача 12). Пусть (k,t)=d. Тогда s*(k/d)=n*(t/d), и числа k/d и t/d являются взаимно простыми, следовательно, n=k/d, а s=t/d. По (*) находим остальные коэффициенты. [Назад] По заданным координатам трех вершин мы можем найти площадь треугольника ABC Sabc=(bx-ay)/2 Если a=0, то минимальная площадь Smin=b/2, если b=0, то Smin=a/2. Если же обе координаты отличны от нуля, то из алгоритма Евклида для нахождения НОД(a,b)=(a,b), следует существование таких целых x и y, что ABS(bx-ay)=(a,b), и именно эти x и y минимизируют площадь треугольника ABC. Нахождение НОД - задача 12. [Назад] Обозначим S=НОД(V1,...,Vn). Если V делится нацело на S, то в сосуд с помощью банок можно налить V литров воды, иначе - нет. [Назад]
k := n; a := 1; b := 0; {инвариант: 0 <= k, f (n) = a * f(k) + b * f (k+1)} while k <> 0 do begin | if k mod 2 = 0 then begin | | l := k div 2; | | {k = 2l, f(k) = f(l), f (k+1) = f (2l+1) = f(l) + f(l+1), | | f (n) = a*f(k) + b*f(k+1) = (a+b)*f(l) + b*f(l+1)} | | a := a + b; k := l; | end else begin | | l := k div 2; | | {k = 2l + 1, f(k) = f(l) + f(l+1), | | f(k+1) = f(2l+2) = f(l+1), | | f(n) = a*f(k) + b*f(k+1) = a*f(l) + (a+b)*f(l+1)} | | b := a + b; k := l; | end; end; {k = 0, f(n) = a * f(0) + b * f(1) = b, что и требовалось} [Назад] В переменной стандартного типа такое большое число не поместится. Будем моделировать возведение 2 в степень n вычисляя последовательно 21, 22, ... , 2n, используя массив. В каждой ячейке массива будем хранить по (например) 4 десятичных цифры числа (т.е. в элементе A[1] - 4 последних цифры числа (разряды 0 -3), в A[2] - 4 предпоследних (разряды 4 - 7) и т.д.). Оценим количество десятичных цифр в числе 2n, n<=1000. Это 10 000 * log10(2) + 1 < 15 000 цифр. Количество элементов массива возьмем равным 15000/4=3750. Введем переменную Nach, в которой будем хранить индекс элемента массива A, в котором находятся старшие значащие разряды вычисляемого сейчас числа. var A: array[1 .. 3750] of word; [Назад] Решается, аналогично задаче 18, моделированием вычисления N1, N2, ... , NN. [Назад] Мы можем представить N! в виде произведения простых сомножителей: N!=2A2*3A3*5A5*7A7*..., где Ap - показатель степени, с которой простое число р входит в разложение. Видно, что нулей в конце числа столько же, сколько нулей в конце произведения 2A2*5A5, но так как, очевидно, что A2>A5, то количество нулей равно A5. Для того, чтобы найти A5, необходимо вычислить сумму +... , где - целая часть числа, т.к. каждое пятое число в произведении N! делится на 5, каждое двадцать пятое число еще раз делится на 5, каждое 53 число, еще раз делится на 5, и т.д. То есть в (*) мы находим, сколько чисел в произведении N! делится на 5. Фрагмент программы выглядит следующим образом : k:=5; После работы цикла в переменной S будет находиться A5. [Назад] Найдем простые множители числа P. Пусть это будут p1,..., pK. Для каждого множителя pI найдем число sI - степень, с ко торой pI входит в разложение P на простые сомножители. Как и в задаче 21 найдем максимальные числа m1, ..., mK, такие что N! делится на pI в степени mI, но не делится на pI в степени mI+1. Получаем для нахождения m следующее уравнение: , где R=N!/[(p1m1)*(p2m2)*...*(pkmk)]. Минимальное из чисел mi div si и даст искомую степень M. Рассмотрим пример: N=15, P=135. Получаем, что M=min{6 div 3, 3 div 1}=2. Объясните, почему мы не можем применить формулу M=N div P + N div P2 + N div P3 + ... ? Приведем полностью программу, реализующую этот алгоритм. { Условие задачи. Примечание. 1. Числа N и P так велики, что нет смысла считать значение N!. uses crt; { Описание задачи. Если взять два любых натуральных числа a и b, то a будет делиться на b, если все степени множителей при разложении числа a на простые множители больше либо равны аналогичных степеней, получаемых при разложении числа b. Пример : 120 = 2*2*2 * 3 * 5 Следовательно, n! делится на p в степени m, если степень любого простого число mn (2<=mn<=p) в разложении числа n! на простые множители больше, чем в аналогичном разложении числа p в степени m. Если F(i,p) - степень простого числа i в разложении числа p на простые множители, то F(i,pm)=F(i,p)*m. Отсюда алгоритм решения : Степень m будет равна целой части от минимального отношения степени простого числа i в разложении n! к степени числа i в разложении числа p, где 2<=i<=p. Алгоритм разложения числа р на простые множители достаточно прост. Основную трудность представляет алгоритм разложения числа n!. алгоритм степень_простого_числа_в_разложении_числа_n! (нат n,mn,s,k) [Назад] Воспользуемся тем, что для n>=4 выполняется неравенство n<=(n-2)*2, т.е. разбивать число на слагаемые, большие 3, не имеет смысла. Выделяем из числа n слагаемые-двойки, пока не получим остаток меньший либо равный 3 (остаток может быть либо 3, либо 2). Так как 2*2*2<3*3, то заменим каждые три двойки на две тройки. По лученное разложение и является искомым. Разберите самостоятельно случаи 1) когда необходимо максимизировать произведение, и слагаемые в разложении числа n должны принадлежать промежутку [A,B], A и B вводятся пользователем. 2) когда необходимо минимизировать произведение, и слагаемые в разложении числа n должны принадлежать промежутку [A,B], A и B вводятся пользователем. [Назад] Если S>=4 то существуют единственные S1 и S2, такие что S=S1*S2=S1+S2. Более того, наименьшее из S1 и S2 больше 1 и <=2: S1=(S/2, S2=(S+)/2, (S-4)2=S2-8*S+16<=S2-4*S<(S-2)2 и 1<S1=(S-)/2<=2. Итак, если r<4 то разложение на множители закончено, иначе проводим разложение r на два множителя, один из них <=2 (и тем более <4 ), если другой <4 , то процесс закончен, иначе повторяем факторизацию S до тех пор, пока не получим искомое разложение. [Назад] Из теоремы Виета получаем, что X1*x2*x3*x4*x5=-A(0)/A(5), откуда следует, что число xi должно быть делителем A(0)/A(5). Находим все делители A(0)/A(5)=R (Если A(0)=A(1)=...=A(i)=0, то i+1 корень уравнения равен 0. Мы делим уравнение на x(i+1), дальше ищем делители числа r=A(i+1)/A(5)). i:=1; [Назад] Пусть m/n - текущая несократимая дробь. Покажем, как найти следующую по значению дробь. Понятно, что она будет среди несокра тимых дробей вида k/р, где р может принимать значения от 2 до 15. Учитывая условие k/р > m/n можно для каждого р прямо вычислять ми нимальное значение k следующим образом: k=m*p/n+1. При этом каждая дробь k/р, полученная описанным выше образом, несократима. m:=0; n:=1 [Назад] Это условие - равенство нулю суммы всех чисел. Мы всегда можем "перетащить" с помощью последовательности ходов все ненулевые числа, помечающие вершины, в одну какую-либо вершину. Если сумма всех чисел равна 0, то после этих ходов окажется, что во всех вершинах записан 0. [Назад] а). Программа вычисления следующая: P:=a[N] Посмотрите, как эта схема работает, вручную найдя значение полинома по его коэффициентам и точке x. b). Решается аналогично. [Назад] Продемонстрируем метод нахождения коэффициентов полинома на примере возведения p(x)=(x2+2*x+1) в четвертую степень. Будем последовательно возводить полином в степени 2, 3,4. Для второй степени справедливо равенство p(x)*p(x)=(x2+2x+1)*(x2+2x+1)=(x2+2x+1)*x2+ +(x2+2x+1)*2x+(x2+2x+1)*1 Будем складывать коэффициенты у одинаковых степеней x, выписывая коэффициенты полинома первой степени с соответствующим сдвигом и умножаем на коэффициент:
выписывая со сдвигом коэффициенты полинома степени i, умноженные на соответствующие коэффициенты исходного полинома, а затем складываем их в столбик. [Назад] Решается аналогично предыдущей задаче. Рассмотрите полином p(x)=(x-A[1])*...*(x-A[N]) и вычислите его коэффициенты. На каждом из шагов, в отличие от предыдущей задачи, умножение будет производиться на новый одночлен (x-A[i]). [Назад] Рассмотрим следующую задачу: Разделить полином p(x)=a[n]*xn + ... + a[1]*x+a[0] на v(x)=(x-d), т.е. найти такую константу - остаток r и такое частное s(x)=s[n-1]*x(n-1)+ ... + s[1]*x+s[0], что Делить будем в столбик. Рассмотрим операцию деления полиномов на примере: 3x2+2x+5 x-2 Тут r=21, s(x)=3x+8. Видно, что коэффициент s[n-1] при старшей степени x в s равен коэффициенту при старшей степени x в p, а остальные коэффициенты в s находятся по формулам: s[t-1]=(-d)*s[t]+p[t]; r=(-d)*s[0]+p[0]. В наглядной форме это можно записать в виде так называемой схемы Горнера:
Тогда проведенное выше деление можно записать в следующем виде:
Вернемся к исходной задаче. Приравняем полиномы: p0(x)=a[n]*xn+a[n-1]*x(n-1)+ ... +a[1]*x+a[0]= =b[n](x-d)n+ ... +b[1]*(x-d)+b[0]. Находим остаток от деления полиномов справа и слева от знака равенства на (x-d). Слева все слагаемые, кроме последнего, делятся на (x-d) нацело. Поэтому P0(x)=(x-d)*p1(x)+b[0]. Особенно удобно это записывается в виде схемы Горнера (обратите внимание, что в верхней строке записаны коэффициенты p0, то, что получается в строке ниже - это коэффициенты p1, к которым также можно применить схему Горнера, находя коэффициенты p2, и т.д.) Пример: p(x)=3x2+2x+5, d=-2,
3x2+2x+5=3(x-2)2+14(x-2)+21. [Назад] Пусть f(x)=ax4+bx3+cx2+dx+e. Выразим f(x+1) через f(x): f(x+1)=f(x)+(4ax3+(6a+3b)x2+(4a+3b+2c)x+(a+b+c+d)=f(x)+g(x), где g(x)=Ax3+Bx2+Cx+D. Поступим аналогично и с g(x): g(x+1)=g(x)+(3Ax2+(3A+2B)x+(A+B+C))=g(x)+h(x), где h(x)=A'x2+B'x+C'. Далее: h(x+1)=h(x)+(2A'x+(A'+B'))=h(x)+p(x), где p(x)=A"x+B". p(x+1)=p(x)+A". Имеем: f(x+4)=f(x+3)+g(x+3) Отсюда получаем фрагмент программы: < BLOCK 1 > x:=5; Итак, на каждое значение, начиная с 5, тратится 5 операций сложения. Остается около 1000 операций на вычисление f(1), f(2), f(3), f(4), для инициализации P:=p(1); H:=h(2); G:=g(3); (F:=f(4)); и на вычисление A2:=A". Ясно, что 1000 операций хватит на все эти вычисления. [Назад] Вверх по странице, к оглавлению и навигации.
|