print2. Комбинаторные объекты

printРазбор задачи 90. Реестр перестановок

Для быстрого получения `k`-й перестановки нужно уметь считать количество перестановок из заданных элементов.
Если элементы не повторяются, то количество перестановок равно `n!`.
Если в наборе есть `r` различных элемент, `i`-й элемент из них встречается `n_i` раз, то количество перестановок равно `{n!}/{n_1!*n_2!*…*n_r!}`.
Так как последние элементы при генерации перестановок всегда идут в порядке возрастания, для подсчета количество перестановок можно использовать следующую функцию:
var a:string; { строка }
    n:integer; { длина строки }
    k:int64; { номер искомой перестановки }
function kolper(i:integer);
var j,m:integer;
  r:int64;
begin
  r:=1;
  m:=0; { в какой раз встречается символ a[j] }
  for j:=i to n do
  begin
    r:=r*(j-i+1);
    if (i=j) or (a[j]=a[j-1]) then inc(m)
    else m:=1;
    r:=r div m;
  end;
  kolper:=r;
end;
Теперь для быстрого достижения `k` перестановки можно не выполнять рекурсию, если она не приводит к искомой перестановке.
procedure gen(i:integer);
var j,t:integer;
  r:int64;
begin
  if i>=n then 
  begin
    writeln(a);
    halt; { закончить выполнение программы }
  end;
  for j:=i to n do
  if (i=j) or (a[i]<>a[j]) then 
  begin 
    t:=a[i];
    a[i]:=a[j];
    a[j]:=t;
    r:=kolper(i+1);
    if k<=r then { искомая перестановка здесь }
      gen(i+1) { выполняем рекурсию }
    else { пропускаем вариант }
      k:=k-r;
  end;
  t:=a[i];
  for j:=i+1 to n do
    a[j-1]:=a[j];
  a[n]:=t;
end;
В основной программе выполняем следующие действия:
begin
  readln(a);
  readln(k);
  n:=length(a);
  gen(1);
end.
loading