вторник, 27 сентября 2011 г.

Теория чисел

Есть несколько задач, которые требуют знания из теории чисел. Например, нахождение простых чисел, разложение на простые множители, деление с остатком, НОД и НОК и т.д. Некоторые из них мы разбирали - это простые числа. Рассмотрим другие.
Разложение числа на простые множители.
Например, число 153 = 3*51=3*3*17=3^2 * 17^1.
Итак, нам нужно определить на каждом шаге первое простое число, которое является делителем данного числа. Из теории чисел: наименьший собственный делитель числа N всегда будет простым. Для поиска первого простого делителя числа N воспользуемся следующей функцией:
function simple(n:integer):integer;
var a:integer;
begin
  a:=2;
  while sqr(a)<=n do begin
    if n mod a = 0 then begin simple:=a; exit; end;
    a:=a+1;
  end;
  simple:=n;
end;


var n,a:integer;
begin
  readln(n);
  while n > 1 do
  begin
     a := simple(n);
     n := n div a;
     writeln(a);
  end;
end.

Иногда требуется вывести не все множители (а они иногда повторяются), а только само число и его степень.

var n,a,k:integer;
begin
  readln(n);
  while n > 1 do
  begin
     a := simple(n);
     k:=0;
    while n mod a = 0 do begin
        n := n div a;
        k:=k+1;
     end;
     writeln(a, '^', k);
  end;
end.
Теперь попробуем найти все простые делители N!=1*2*3*...*N.
Пусть N=10, тогда 10!=1*2*3*4*5*6*7*8*9*10. Видно, что степени 2 2=2^1
4=2^2
6=3*2^1
8=2^3
10=5*2^1
Итого 1+2+1+3+1=8. 
Если разделим 10! на 2^1, то получим 5 вхождений (их можно считать так 10 div 2 = 5). Останется (1-1)+(2-1)+(1-1)+(3-1)+(1-1)=0+1+0+2+0=3 степени двойки. Из них 2 раза входит 2^2 (10 div 4 = 2) и один раз 2^3 (10 div 8 = 1). Так делаем для всех простых чисел:
если p - простое, то k = n div p +n div p^2 + n div p^3 +...
function simple(n:integer):boolean;
var i:integer;
begin
  simple:=true;
  if (n mod 2 = 0) and (n<>2) then simple:=false;
  for i:=2 to round(sqrt(n)) do begin
    if i mod 2 = 0 then continue;
    if n mod i = 0 then begin simple:=false; exit; end;
  end;
end;
                  
var i,n,p,k:integer;
begin
read(n);
for i:=2 to n do
  if simple(i) then begin
  p:=i; k:=0;
  while n div p >0 do begin k:=k+ n div p; p:=p*i; end;
  writeln(i,'^',k);
  end;
end.

Деление с остатком. Если даны два натуральных числа P и Q, то можно поделить P на Q с остатком  R  и частным от деления T. Тогда P=T*Q+R. Остатки от деления на одно и то же число можно складывать и умножать:
(P1+P2) mod Q = (P1 mod Q +P2 mod Q) mod Q
(P1*P2) mod Q = ((P1 mod Q )*(P2 mod Q)) mod Q
Пусть заданы два числа N и M. Необходимо найти остаток от деления числа N! на M. Используя выше приведенное условие получим следующий алгоритм решения задачи:
var n,m,t:integer;
begin
  read(n,m);
  t:=1;
  for I:=1 to n do
    t: = (t*i)mod m;
  write(t);
end.

Перейдем к следующей задаче: нахождение НОД (наибольший общий делитель) и НОК (наименьшее общее кратное). Решается такая задача с помощью алгоритма Евклида для двух натуральных чисел а и b:
пока a<>b
   если a<b то b:=a-b
     иначе если a>b то a:=a-b;
Например, НОД(16, 12)
a=16,  b=12

a<>b? да
a<b? нет
a>b? да
a:=a-b=16-12=4

a<>b? да
a<b? да
b:=b-a=12-4=8

a<>b? да
a<b? да
b:=b-a=8-4=4

a<>b? нет
НОД=4

Вычитание можно заменить взятие остатка. Тогда программа имеет вид:
var a,b,nod:integer;
begin
  read(a,b);
  while a<>b do
    if a<b then b:=b mod a
       else if a>b then a:=a mod b;
  nod:=a;
  write(nod);
end.
Но можно написать программу без условий и оформить в виде функции, при этом нужно учесть, что a>b:
function nod(a,b:integer):integer;
var r:integer;
begin
  if b>a then nod:=nod (b,a) else
  begin
  while b<>0 do
   begin
      r:=a mod b;
      a:=b;
      b:=r;
   end;
   nod:=a;
   end;
end;

var a,b:integer;
begin
  read(a,b);write(nod(a,b));
end.
Для нахождения НОК(a,b) воспользуемся формулой НОК(a,b)=a*b/НОД(a,b).
Если нужно найти НОД (или НОК) нескольких чисел, то последовательно находим
НОД( а1, а2, а3, а4) = НОД(НОД(НОД(а1, а2), а3), а4).

1 комментарий:

  1. Г-дин Педро и неговата компанија за заем беше апсолутно одлична за работа. Тој беше исклучително јасен, темелен и трпелив додека ја водеше мојата сопруга и јас низ процесот на позајмување. Тој исто така беше многу навремен и работеше напорно за да се увери дека се е подготвено пред да го затвори заемот.
    Г-дин Педро е службеник за заеми што работи со група инвеститори кои ни помагаат да добиеме средства за да го купиме нашиот нов дом. Можете да контактирате со него ако сакате да добиете заем по прифатлива ниска стапка од 2% RIO   Испратете му е-пошта . pedroloanss@gmail.com

    ОтветитьУдалить