Решить олимпиадную (9кл). олимиада уже но хочется знать решение. программа на паскале. заранее . петя выписал все сочетания из n первых латинских букв по k букв. в каждом сочетании он выписывал буквы в лексикографическом (словарном) порядке. сочетания он выписывал в лексикографическом порядке по одному в строке. надо узнать какое слово записано в m-ой строке. входные данные: целые числа n, k, m (1< =n< =26, 1< =k< =n, а м не превосходит количества всех выписанных сочетаний). выходные данные: вывести м-ое выписанное сочетание. пример: вх: 4 2 3 вых: ad пояснение: все сочетания в порядке их записи: ab ac ad bc bd cd (третьим по счету сочетанием является ad).
Всего число выбрать K элементов из N равно C_N^K ("цэ из N по K").
Поймем, например, надо ли брать 1-й элемент. Всего сочетаний, где первый элемент взят: C_(N-1)^(K-1) {в самом деле, в этом случае осталось выбрать K-1 из оставшихся N-1}; не взят: C_(N-1)^K. Учитывая, что те, в которые первый элемент входит, идут перед теми, в которые он не входит, решаем: если M > C_(N-1)^(K-1), 1-й элемент не берём, иначе берём.
Дальше если 1-й взяли, M оставляем таким же, если нет - уменьшаем на C_(N-1)^(K-1).
Процесс повторяем, пока не найдем все буквы.
Осталось понять, как считать C_N^K. Исходя из рассуждений выше, C_N^K = C_(N-1)^(K-1) + C_(N-1)^K. Кроме того, C_N^0 = 1 для всех N, C_N^K = 0 при K < 0 или K > N. Пользуясь этим, можно найти все C_N^K. Не забываем про длинную арифметику: C_N^K может не влезать в обычные типы данных. Я буду писать на PascalABC.NET, там длинная арифметика есть - тип BigInteger, если нет - легко найти, как это писать. (Update: в данном случае всё влезет в longint - биномиальные коэффициенты не превысят 10 миллионов с небольшим).
Итак, вот и искомый код:
begin
var N, K: integer;
read(N, K);
var M := ReadString().ToBigInteger();
var C: array[,] of BigInteger := new BigInteger[N, K];
for var j := 1 to K - 1 do
C[0, j] := 0;
for var i := 0 to N - 1 do
C[i, 0] := 1;
for var i := 1 to N - 1 do
for var j := 1 to K - 1 do
C[i, j] := C[i - 1, j] + C[i - 1, j - 1];
var possible := 'a';
while K > 0 do
begin
if M <= C[N - 1, K - 1] then
begin
write(possible);
dec(K);
end
else
M := M - C[N - 1, K - 1];
dec(N);
inc(possible);
end;
end.
Без BigInteger:
begin
var N, K: integer;
var M: longint;
read(N, K, M);
var C: array[,] of longint := new longint[N, K];
for var j := 1 to K - 1 do
C[0, j] := 0;
for var i := 0 to N - 1 do
C[i, 0] := 1;
for var i := 1 to N - 1 do
for var j := 1 to K - 1 do
C[i, j] := C[i - 1, j] + C[i - 1, j - 1];
var possible := 'a';
while K > 0 do
begin
if M <= C[N - 1, K - 1] then
begin
write(possible);
dec(K);
end
else
M := M - C[N - 1, K - 1];
dec(N);
inc(possible);
end;
end.
b:array[1..26] of boolean;
procedure writesymbol(j:longint);
begin
write(chr(ord('a')+j-1));
end;
procedure print(x:longint);
var z,h,p:longint;
begin
z := 0;
p := 0;
while true do
begin
p := p + 1;
if b[p] = false then z := z + 1;
if z = x then break;
end;
x := p;
b[x] := true;
writesymbol(x);
end;
function fa_l(a,b:longint):longint;
var s,h:longint;
begin
s := 1;
for h := a to b do s := s * h;
fa_l := s;
end;
begin
read(n,k,m);
d := fa_l(n-k+1,n-1);
for i := k downto 1 do
begin
print((m - 1) div d + 1);
if m mod d = 0 then m := d else
m := m mod d;
d := d div (n - (k - i + 1));
end;
end.