Количество сюрпризов


16

задача

Дано 2 натуральных числа nи k, где n > k, выведите количество сюрпризов из набора nразличимых элементов в набор kразличимых элементов.

Определение

Функция f: S → T называется сюръекцией, если для каждого t∈T существует s∈S, такое что f (s) = t.

пример

Когда n=3и k=2, вывод 6, так как есть 6сюрпризы от {1,2,3}до {1,2}:

  1. 1↦1, 2↦1, 3↦2
  2. 1↦1, 2↦2, 3↦1
  3. 1↦1, 2↦2, 3↦2
  4. 1↦2, 2↦1, 3↦1
  5. 1↦2, 2↦1, 3↦2
  6. 1↦2, 2↦2, 3↦1

Testcases

n k output
5 3 150
8 4 40824
9 8 1451520

Ссылка

счет

Это . Кратчайший ответ в байтах побеждает.

Применяются стандартные лазейки .


11
Определение сюрприза было бы неплохо.
Стьюи Гриффин

3
Это намеренно, что п не может равняться к ?
Деннис

1
@ Денис Мне нравится исключать все возможные крайние случаи из моих испытаний
Лики Монахиня,

3
Это похоже на важный крайний случай для включения. Я предполагаю, что большинство ответов, которые работают для n> k, также будут работать для n == k, но это может позволить некоторую подлую
игру в

@ Кто бы ни голосовал, чтобы закрыть, что твоя причина?
Дилнан

Ответы:


5

Желе , 5 4 байта

ṗṬML

Это решение для грубой силы O (k n ) .

Попробуйте онлайн!

Как это устроено

ṗṬML  Main link. Left argument: k. Right argument: n.

ṗ     Cartesian power; yield the list of all n-tuples over {1, ..., k}.
      Each tuple represents a (not necessarily surjective) function from
      {1, ..., n} to {1, ..., k}.
 Ṭ    Apply the "untruth" atom to each tuple.
      Ṭ maps a list of indices to an array with 1's at those indices, and exactly
      as many zeroes as needed to build the array.
      Examples:
           [1, 2, 3, 3, 3] -> [1, 1, 1]
           [1, 3, 5]       -> [1, 0, 1, 0, 1]
           [2, 6, 2, 4, 4] -> [0, 1, 0, 1, 0, 1]
  M   Yield all indices of maximal elements, i.e., all indices of [1] * k.
   L  Take the length.

4

Haskell , 48 байтов

s(_,1)=1
s(1,_)=0
s(m,n)=n*(s(m-1,n-1)+s(m-1,n))

Попробуйте онлайн!

Почему подсчет сюрпризов s(m,n)=n*s(m-1,n-1)+n*s(m-1,n)?

для того, чтобы собирать nизображения, я могу либо

  • втиснуть одноэлементное [m]творение в любую из nграниц окружающих n-1групп
  • или добавить мой новый mв любую из nуже существующих групп[1..m-1]

Haskell , 38 байт

m#n|n<2=1|m<2=0|o<-m-1=n*(o#(n-1)+o#n)

Попробуйте онлайн!


2
38 байт с помощью инфиксного оператора: попробуйте онлайн!
Лайкони

4

Lean , 66 байт

def s:_->nat->nat|(m+1)(n+1):=(n+1)*(s m n+s m(n+1))|0 0:=1|_ _:=0

Попробуйте онлайн!


Доказательство правильности

Попробуйте онлайн!


объяснение

Давайте раскроем функцию:

def s : nat->nat->nat
| (m+1) (n+1) := (n+1)*(s m n + s m (n+1))
| 0     0     := 1
| _     _     := 0

Функция определяется сопоставлением с образцом и рекурсией, оба из которых имеют встроенную поддержку.

Мы определяем s(m+1, n+1) = (n+1) * (s(m, n) + s(m, n+1)и s(0, 0) = 1, который оставляет открытым, s(m+1, 0)и s(0, n+1), оба из которых определены 0в последнем случае.

Постные использует синтаксис lamdba исчисления, так s m nэто s(m, n).


Теперь доказательство правильности: я сформулировал это двумя способами:

def correctness : ∀ m n, fin (s m n) ≃ { f : fin m → fin n // function.surjective f } :=
λ m, nat.rec_on m (λ n, nat.cases_on n s_zero_zero (λ n, s_zero_succ n)) $
λ m ih n, nat.cases_on n (s_succ_zero m) $ λ n,
calc fin (s (nat.succ m) (nat.succ n))
   ≃ (fin (n + 1) × (fin (s m n + s m (n + 1)))) :
  (fin_prod _ _).symm
... ≃ (fin (n + 1) × (fin (s m n) ⊕ fin (s m (n + 1)))) :
  equiv.prod_congr (equiv.refl _) (fin_sum _ _).symm
... ≃ (fin (n + 1) × ({f : fin m → fin n // function.surjective f} ⊕
         {f : fin m → fin (n + 1) // function.surjective f})) :
  equiv.prod_congr (equiv.refl _) (equiv.sum_congr (ih n) (ih (n + 1)))
... ≃ {f // function.surjective f} : s_aux m n

def correctness_2 (m n : nat) : s m n = fintype.card { f : fin m → fin n // function.surjective f } :=
by rw fintype.of_equiv_card (correctness m n); simp

Первый - это то, что на самом деле происходит: биекция между [0 ... s(m, n)-1]и наложения [0 ... m-1]на [0 ... n-1].

Второй, как обычно говорят, это s(m, n)кардинальность выводов [0 ... m-1]на [0 ... n-1].


Lean использует теорию типов в качестве своей основы (вместо теории множеств). В теории типов каждый объект имеет свойственный ему тип. natтип натуральных чисел, а утверждение, которое 0является натуральным числом, выражается как 0 : nat. Мы говорим , что 0это типа nat, и natимеет 0как житель.

Предложения (утверждения / утверждения) также являются типами: их обитатель является доказательством предложения.


  • defМы собираемся ввести определение (потому что биекция - это действительно функция, а не просто суждение).

  • correctness: название определения

  • ∀ m n: для каждого mи n(Lean автоматически делает вывод, что их тип nat, из-за того, что следует).

  • fin (s m n)это тип натуральных чисел, который меньше, чем s m n. Чтобы сделать обитателя, нужно предоставить натуральное число и доказательство того, что оно меньше, чем s m n.

  • A ≃ B: биекция между типом Aи типом B. Сказать, что биекция вводит в заблуждение, поскольку на самом деле нужно предоставить обратную функцию.

  • { f : fin m → fin n // function.surjective f }тип сюрпризов от fin mдо fin n. Этот синтаксис создает подтип из типа fin m → fin n, то есть типа функций из fin mв fin n. Синтаксис есть { var : base type // proposition about var }.

  • λ m: ∀ var, proposition / type involving varдействительно функция, которая принимает varв качестве входных данных, поэтому λ mвводит ввод. ∀ m n,это сокращение для∀ m, ∀ n,

  • nat.rec_on m: сделать рекурсию на m. Чтобы определить что-то для m, определите вещь для, 0а затем с учетом вещи k, построить вещь для k+1. Можно заметить, что это похоже на индукцию, и на самом деле это результат переписки Чёрча-Говарда . Синтаксис есть nat.rec_on var (thing when var is 0) (for all k, given "thing when k is k", build thing when var is "k+1").

Хех, это становится длинным, и я только на третьей линии correctness...


3

J , 19 байт

-/@(^~*]!0{])],i.@-

Попробуйте онлайн!

объяснение

-/@(^~*]!0{])],i.@-  Input: n (LHS), k (RHS)
                  -  Negate k
               i.@   Range [k-1, k-2, ..., 0]
             ]       Get RHS
              ,      Join, forms [k, k-1, ..., 0]
   (        )        Dyad between n (LHS), [k, k-1, ..., 0] (RHS)
           ]           Get RHS
         0{            Select value at index 0
       ]               Get RHS
        !              Binomial coefficient
    ^~                 Raise each in RHS to power of n
      *                Multiply
-/@                  Reduce from right to left using subtraction (forms alternating sum)

-/@(^~*]!0{])]-i.
FrownyFrog

2

R , 49 байт

function(n,k,j=0:k)((-1)^(k-j)*j^n)%*%choose(k,j)

Попробуйте онлайн!

Реализует одну из формул Марио Каталани:

T(n, k) = Sum_{j=0..k} (-1)^(k-j)*j^n*binomial(k, j)

или поочередно:

T(n, k) = Sum_{j=0..k} (-1)^j*binomial(k, j)*(k-j)^n

что дает тот же счетчик байтов в R.


2

Python 2 , 56 53 50 байт

f=lambda n,k:n/k and(1/k or f(n-1,k-1)+f(n-1,k))*k

Попробуйте онлайн!

-3 байта благодаря H.PWiz.

-3 байта благодаря Деннису.

  • Если n<kне все kможно отобразить, то нет никаких сюрпризов. n/k andзаботится об этом.
  • Взятие f(0,0)=1дает нам единственный ненулевой базовый случай, который нам нужен. 1/k orдобивается этого.


2

Brain-Flak , 142 байта

({}<({}()){({}[(())]<<>{({}({})<>)<>}{}>)}{}>)<>{<>(({}<>)<{({}[()]<([])({([{}]()({}))([{}]({}))}{}[{}])>)}{}({}<>)>)<>}<>{}{}{({}<>[{}])<>}<>

Попробуйте онлайн!

При этом используется стандартная формула включения-исключения.

Я не могу написать полное объяснение в настоящее время, но вот объяснение высокого уровня:

# Compute k-th row of Pascal's triangle
({}<({}()){({}[(())]<<>{({}({})<>)<>}{}>)}{}>)<>

# Multiply each element by n^j (and reverse to other stack)
{<>(({}<>)<{({}[()]<([])({([{}]()({}))([{}]({}))}{}[{}])>)}{}({}<>)>)<>}

# Compute alternating sum
<>{}{}{({}<>[{}])<>}<>




Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.