module Enumerable
def tally(h = {})
each_with_object(h) {|x, h| h[x] = (h[x] || 0) + 1}
end
end
def cumsum(a)
a.inject([]) {|acc, x| acc << (acc.last || 0) + x}
end
def n_permutations(a)
factrial = ->n {(1..n).inject(:*) || 1}
factrial.(a.size) / a.tally.values.map(&factrial).inject(:*)
end
def next_or_nil(a)
(a.size - 2).downto(0).each_with_object(nil) {|i, _|
next if not j = (i + 1...a.size).find {|j| 2 <= a[j] - a[i]}
return a.dup.tap {|a|
a[i] += 1; a[j] -= 1
loop {
j = (i + 1...a.size).find {|j| a[i] < a[j]}
k = j && (a.size - 1).downto(j + 1).find {|k| a[j] <= a[k] && a[k] < 5}
break if !k
a[j] -= 1; a[k] += 1
}
}
}
end
def nexts(a)
a && [a].tap {|b| b << a while a = next_or_nil(a)}
end
def initial(s, w = nil)
w ||= s.divmod(5).tap {|q, r| break q + (r == 0 ? 0 : 1)}
q, r = (s - w).divmod 4
0 < w && w <= s && s <= w * 5 && (r == 0 || q + 1 <= w) && Array.new(w, 1).tap {|b|
(1..q).each {|i| b[-i] += 4}
b[-q -1] += r if 0 < r
} || nil
end
def f(m, n)
count_permutations = ->s, w {
nexts(initial(s, w))&.map(&method(:n_permutations))&.sum || 0
}
aux = ->acc, b, s, w {
return acc if !b || s < 1 || w < 1
c = cumsum((1..5).map {|hd| count_permutations.(s - hd, w - 1)}).prepend(0)
hd = c.index {|c| n <= b + c} || s
aux.(acc << hd, b + c[hd - 1], s - hd, w - 1)
}
c = cumsum((1..m).map {|w| count_permutations.(m, w)}).prepend(0)
w = c.index {|c| n <= c}
b = w && c[w - 1]
aux.([], b, m, w).join.to_i
end
g = ->m, n {puts "(#{m},#{n}) → #{f(m, n)}"}
g.(2,1)
g.(2,2)
g.(2,3)
g.(20,1)
g.(20,2)
g.(20,3)
g.(20,400096)
g.(20,400097)
g.(32,1)
g.(32,2)
g.(32,3)
g.(32,1000)
g.(32,1000000)
g.(32,1000000000)
g.(32,1333610936)
g.(32,1333610937)
bW9kdWxlIEVudW1lcmFibGUKICBkZWYgdGFsbHkoaCA9IHt9KQogICAgZWFjaF93aXRoX29iamVjdChoKSB7fHgsIGh8IGhbeF0gPSAoaFt4XSB8fCAwKSArIDF9CiAgZW5kCmVuZApkZWYgY3Vtc3VtKGEpCiAgYS5pbmplY3QoW10pIHt8YWNjLCB4fCBhY2MgPDwgKGFjYy5sYXN0IHx8IDApICsgeH0KZW5kCmRlZiBuX3Blcm11dGF0aW9ucyhhKQogIGZhY3RyaWFsID0gLT5uIHsoMS4ubikuaW5qZWN0KDoqKSB8fCAxfQogIGZhY3RyaWFsLihhLnNpemUpIC8gYS50YWxseS52YWx1ZXMubWFwKCZmYWN0cmlhbCkuaW5qZWN0KDoqKQplbmQKZGVmIG5leHRfb3JfbmlsKGEpCiAgKGEuc2l6ZSAtIDIpLmRvd250bygwKS5lYWNoX3dpdGhfb2JqZWN0KG5pbCkge3xpLCBffAogICAgbmV4dCBpZiBub3QgaiA9IChpICsgMS4uLmEuc2l6ZSkuZmluZCB7fGp8IDIgPD0gYVtqXSAtIGFbaV19CiAgICByZXR1cm4gYS5kdXAudGFwIHt8YXwKICAgICAgYVtpXSArPSAxOyBhW2pdIC09IDEKICAgICAgbG9vcCB7CiAgICAgICAgaiA9IChpICsgMS4uLmEuc2l6ZSkuZmluZCB7fGp8IGFbaV0gPCBhW2pdfQogICAgICAgIGsgPSBqICYmIChhLnNpemUgLSAxKS5kb3dudG8oaiArIDEpLmZpbmQge3xrfCBhW2pdIDw9IGFba10gJiYgYVtrXSA8IDV9CiAgICAgICAgYnJlYWsgaWYgIWsKICAgICAgICBhW2pdIC09IDE7IGFba10gKz0gMQogICAgICB9CiAgICB9CiAgfQplbmQKZGVmIG5leHRzKGEpCiAgYSAmJiBbYV0udGFwIHt8YnwgYiA8PCBhIHdoaWxlIGEgPSBuZXh0X29yX25pbChhKX0KZW5kCmRlZiBpbml0aWFsKHMsIHcgPSBuaWwpCiAgdyB8fD0gcy5kaXZtb2QoNSkudGFwIHt8cSwgcnwgYnJlYWsgcSArIChyID09IDAgPyAwIDogMSl9CiAgcSwgciA9IChzIC0gdykuZGl2bW9kIDQKICAwIDwgdyAmJiB3IDw9IHMgJiYgcyA8PSB3ICogNSAmJiAociA9PSAwIHx8IHEgKyAxIDw9IHcpICYmIEFycmF5Lm5ldyh3LCAxKS50YXAge3xifAogICAgKDEuLnEpLmVhY2gge3xpfCBiWy1pXSArPSA0fQogICAgYlstcSAtMV0gKz0gciBpZiAwIDwgcgogIH0gfHwgbmlsCmVuZApkZWYgZihtLCBuKQogIGNvdW50X3Blcm11dGF0aW9ucyA9IC0+cywgdyB7CiAgICBuZXh0cyhpbml0aWFsKHMsIHcpKSYubWFwKCZtZXRob2QoOm5fcGVybXV0YXRpb25zKSkmLnN1bSB8fCAwCiAgfQogIGF1eCA9IC0+YWNjLCBiLCBzLCB3IHsKICAgIHJldHVybiBhY2MgaWYgIWIgfHwgcyA8IDEgfHwgdyA8IDEKICAgIGMgPSBjdW1zdW0oKDEuLjUpLm1hcCB7fGhkfCBjb3VudF9wZXJtdXRhdGlvbnMuKHMgLSBoZCwgdyAtIDEpfSkucHJlcGVuZCgwKQogICAgaGQgPSBjLmluZGV4IHt8Y3wgbiA8PSBiICsgY30gfHwgcwogICAgYXV4LihhY2MgPDwgaGQsIGIgKyBjW2hkIC0gMV0sIHMgLSBoZCwgdyAtIDEpCiAgfQogIGMgPSBjdW1zdW0oKDEuLm0pLm1hcCB7fHd8IGNvdW50X3Blcm11dGF0aW9ucy4obSwgdyl9KS5wcmVwZW5kKDApCiAgdyA9IGMuaW5kZXgge3xjfCBuIDw9IGN9CiAgYiA9IHcgJiYgY1t3IC0gMV0KICBhdXguKFtdLCBiLCBtLCB3KS5qb2luLnRvX2kKZW5kCmcgPSAtPm0sIG4ge3B1dHMgIigje219LCN7bn0pIOKGkiAje2YobSwgbil9In0KZy4oMiwxKQpnLigyLDIpCmcuKDIsMykKZy4oMjAsMSkKZy4oMjAsMikKZy4oMjAsMykKZy4oMjAsNDAwMDk2KQpnLigyMCw0MDAwOTcpCmcuKDMyLDEpCmcuKDMyLDIpCmcuKDMyLDMpCmcuKDMyLDEwMDApCmcuKDMyLDEwMDAwMDApCmcuKDMyLDEwMDAwMDAwMDApCmcuKDMyLDEzMzM2MTA5MzYpCmcuKDMyLDEzMzM2MTA5MzcpCg==