Составить программу вычисления числа размещений из N элементов по M, без использования готовых функций

Нужно использовать строковый тип данных(числа перевести в строку), т.к. числовой тип не сможет решить задачу при N>10000 и M>100 это будет выход из границ. Либо другим способом чтобы n и m при вводе были такими как описано выше.

Помогите пожалуйста написать программу на Pascal. Ответ необходимо записать в txt файл в котором будет ответ (огромное число).

Материал к задаче:

В теории чисел могут понадобится вычисления с большими целыми числами. При этом очень важным является сохранение всех значащих цифр. Имеющиеся во всех языках программирования числовые типы имеют ограниченную длину разрядной сетки. При ее превышении происходит либо округление, либо просто отбрасывание последующих цифр. Реализовать операции с многоразрядными числами без потери значащих цифр можно двумя способами. а) Запоминать каждое число в массиве. При этом, каждый элемент массива будет хранить одну цифру числа. б) Запоминать числа в виде строк. Рассмотрим второй способ. В этом случае необходимо реализовать базовые алгебраические операции над числами-строками – сложение, вычитание, умножение, целочисленное деление и вычисление остатка от целочисленного деления. При разработке программ, работающих с длинными числами целесообразно эти базовые операции реализовать в виде отдельных функций и затем уже использовать их в основной программе. Алгоритмы реализации просто повторяют алгоритмы вычислений «столбиком», которые осваиваются в младших классах начальной школы. Например, для операции сложения: В цикле, начиная с последнего символа (цифры) и кончая первым

  • каждая пара символов преобразуется в числа - х1 и х2;
  • эти числа складываются
  • при этом переменная р следит за тем, что не была сумма предыдущей пары чисел больше 9. Если «да», то к х добавляется 1;
  • если х больше 9, то в качестве результата сложения берется вторая цифра, а переменная р принимает значение “True” (один в уме);
  • если х меньше 10, переменная р принимает значение “False”; По окончании цикла, если «в уме» еще что-то есть, впереди к результату добавляется 1. Если есть возможность выбора между языками программирования, то лучше выбирать Паскаль – уж слишком неуклюжи операции со строками в Бейсике (хотя все это дело вкуса и привычки). Итак, пусть имеются два длинных числа, представленных в виде строк. Тогда программная реализация операций сложения и вычитания в виде функции может выглядеть следующим образом (Паскаль).

{ Выравнивание длин чисел }

Procedure Equel(Var s1,s2:string;Var l:integer);
Var i,l1,l2:integer;
begin
   l1:=Length(s1);
   l2:=Length(s2);
   If l1>l2 then begin
               l:=l1;
               For i:=1 to l-l2 do s2:='0'+s2
            end
            else begin
               l:=l2;
               For i:=1 to l-l1 do s1:='0'+s1
            end
end;

{ Сложение }

Function Plus(a,b:string):string;
Var i,k,l:integer;
    x,x1,x2:integer;
    s,c:string;
    p:boolean;
begin
    Equel(a,b,l);
    p:=False;
    s:='';
    For i:=l Downto 1 do
    begin
   Val(a[i],x1,k);
   Val(b[i],x2,k);
   x:=x1+x2;If p then x:=x+1;
   If x>9 then p:=True else p:=False;
   x:=x mod 10;
   Str(x,c);
   s:=c+s
end;
If p then s:='1'+s;
Plus:=s
end;

{ Вычитание }

Function Minus(a,b:string):string;
Var i,k,l:integer;
    x,x1,x2:integer;
    s,c:string;
    p:boolean;
begin
    Equel(a,b,l);
    p:=False;
    s:='';
    For i:=l Downto 1 do
    begin
  Val(a[i],x1,k);
  Val(b[i],x2,k);
  If p then x1:=x1-1;
  If x1<x2 then begin x1:=x1+10;p:=True end
           else p:=False;
  x:=x1-x2;
  Str(x,c);
  s:=c+s
    end;
    While (s[1]='0') and (Length(s)>1) do Delete(s,1,1);
    Minus:=s
end;

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

Uses Crt;
Var a,b:string;
    i:integer;
Procedure Equel …
…
…
Function Plus …
…
…
Begin
   ClrScr;
   a:='1';                  {Количество зерен в клетке                 }
   b:=a;                        {Общее количество зерен                    }
   For i:=1 to 63 do
   begin
a:=Plus(a,a);               {Умножение на 2                                  }
b:=Plus(b,a)                {Сложение с остальными                     }
   end;
   Insert(',',b,Length(b)-5);       {Перевод в тонны – вставка запятой  }
   Writeln(b+' тонн');
   Readkey
end.

Результат – 18446744073709,551615 тонн.

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

Реализация перемножения столбиком (PascalABC).

// Умножение числа на одну цифру
Function MultiOne(a:string;b:integer):string;
Var i,j:integer;
    s,s1:string;
    x:integer;
begin
    s:='';
    For i:=Length(a) Downto 1 do begin
       x:=StrToInt(a[i]);
       x:=x*b;
       s1:=IntToStr(x);
       For  j:=1 to (Length(a)-i) do s1:=s1+'0';
       s:=Plus(s,s1)
    end;
    MultiOne:=s
end;

// Перемножение
Function Multi(a,b:string):string;
Var i,j:integer;
    s1,s:string;    
begin
    s:='';
    For i:=Length(b) Downto 1 do begin
      s1:=MultiOne(a,StrToInt(b[i]));
      For j:=1 to (Length(b)-i) do s1:=s1+'0';
      s:=Plus(s,s1)
    end;
    Multi:=s
end;

Ответы (1 шт):

Автор решения: Archery

Не чистый паскаль, а PascalABC.Net, но без использования .Net библиотек. Старалась по крайней мере.

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

// Возвращает n-ую с конца цифру или 0
function GetFromRight(s: string; n: integer): integer;
begin
    var l := Length(s);
    if (n > l) or (n <= 0) then Result := 0 else Result := StrToInt(s[l - n + 1]);
end;

// Убираем лишние нули вначале
function RemoveLeftZeros(s: string): string;
begin
    while (Length(s) > 1) and (s[1] = '0') do Delete(s, 1, 1);
    Result := s;
end;

function Plus(a, b: string): string;
begin
    var ten := 0; //признак изменения десятков
    var res := '';
    
    for var i := 1 to max(Length(a), Length(b)) do
    begin
        var x := GetFromRight(a, i) + GetFromRight(b, i) + ten;
        ten := x div 10;
        res := IntToStr(x mod 10) + res;
    end;
    
    if ten > 0 then res := IntToStr(ten) + res;
    Result := RemoveLeftZeros(res);
end;

function Minus(a, b: string): string;
begin
    var ten := False;
    var res := '';
    
    for var i := 1 to max(Length(a), Length(b)) do
    begin
        var xa := GetFromRight(a, i);
        var xb := GetFromRight(b, i);
        
        if ten then xa := xa - 1;
        ten := xa < xb;
        if ten then xa := xa + 10;
        
        res := IntToStr(xa - xb) + res;
    end;
    
    if ten then Result := '-' + Minus(b, a) else Result := RemoveLeftZeros(res);
end;

// Умножение числа на одну цифру
function Multiply(a: string; n: integer): string;
begin
    n := n mod 10; // на всякий пожарный
    var res := '';
    var ten := 0;
    for var i := Length(a) downto 1 do
    begin
        var x := StrToInt(a[i]) * n + ten;
        ten := x div 10;
        res := IntToStr(x mod 10) + res;
    end;
    if ten > 0 then res := IntToStr(ten) + res;
    Result := RemoveLeftZeros(res);
end;

// Yмножение
function Multiply(a, b: string): string;
begin
    var res := '';
    for var i := Length(b) downto 1 do
    begin
        var s1 := Multiply(a, StrToInt(b[i]));
        for var j := 1 to (Length(b) - i) do 
            s1 := s1 + '0';
        res := Plus(res, s1);
    end;
    Result := RemoveLeftZeros(res);
end;

procedure Test();
begin
    for var a := 0 to 110 do
    begin
        PrintLn('a = ', a);
        for var b := 10200 to 10345 do
        begin
            var sa := IntToStr(a);
            var sb := IntToStr(b);
            
            var t := plus(sa, sb);
            if t <> IntToStr(a + b) then WriteLnFormat('{0} + {1} = {2} | {3}', a, b, a + b, t);
            
            t := minus(sa, sb);
            if t <> IntToStr(a - b) then WriteLnFormat('{0} - {1} = {2} | {3}', a, b, a - b, t);
            
            if a < 10 then begin
                t := Multiply(sb, a);
                if t <> IntToStr(a * b) then WriteLnFormat('{0} * {1} = {2} | {3} ', b, a, a * b, t);
            end;
            
            t := Multiply(sa, sb);
            if t <> IntToStr(a * b) then WriteLnFormat('{0} * {1} = {2} | {3}: ', a, b, a * b, t);
        end;
    end;
end;

//задачя о зернах на шахматной доске
function WheatAndChessboardProblem(): string;
begin
    var current_cell := '01'; //Количество зерен на клетке
    var sum := current_cell; //Общее количество зерен
    
    for var i := 2 to 64 do
    begin
        current_cell := Multiply(current_cell, 2); //Умножение на 2
        sum := Plus(sum, current_cell); //Сложение с остальными
    end;
    
    var ves := Multiply(sum, '65'); // одно зёрнышко пшеницы имеет массу 0,065 грамма
    Insert('.', ves, Length(ves) - 9 + 1); // Перевод в тонны, делим на 1е9
    
    Result := sum + ' зерен' + chr(13) + ves + ' тонн пшеницы';
end;

//Количество размещений без повторений = n * (n-1) * (n-2) * ... * (n-m+1) = n!/(n-m)!
function CountPermutations(n: string; m: integer): string;
begin
    var A := '01';
    for var i := 0 to m - 1 do
    begin
        var x := Minus(n, IntToStr(i));
        A := Multiply(A, x);
    end;
    
    Result := 'A = ' + A;
end;

begin
    //    Test();
    WriteAllText('result.txt', WheatAndChessboardProblem());
    WriteAllText('result.txt', CountPermutations('2343', 292));
end.

Вывод:

18446744073709551615 зерен

1199038364791.120854975 тонн пшеницы

и

A = 5621020464221928081622596846312979894386396770390213138833519820801312892717218260705821410899957656193532367187812625175169950728458223021700671049119063882650289310073663931121529174633862319495473968748420439049798273258619051330907291415548617057214205215113540305221124312373237470322114930522810430007231900870006888557940326348641980146874452760708096917684962292294038928239614281031440555480320270358118366277307373773731746329635734415141151648443101133481615732096247619289444695068418921081554005451949797687871362483531092377657996760178567103420740723160785502249941837483511681488579247893487183598849265463814419823980261412706260621769699366046977852327732061227636668451747633024873964924955658921192743966188915442852068289253728160682403345773402505230975019974271304498395650496962625556368227828940477698331245097688884413644819470388094010547057574302724450437205988785290815628902400000000000000000000000000000000000000000000000000000000000000000000000

→ Ссылка