using System;
using System.Numerics;
using System.Collections.Generic;
public class Test
{
// Helper functions for calculating values of (n choose k).
// These are not optimally coded!
// ----------------------------------------------------------------------
protected static BigInteger factorial(int n) {
BigInteger f = 1;
while (n > 1) f *= n--;
return f;
}
protected static int binomial(int n, int k) {
if (k > n) return 0;
return (int)(factorial(n) / (factorial(k) * factorial(n-k)));
}
// In the combinatorial number system, a combination {c_1, c_2, ..., c_k}
// corresponds to the integer value obtained by adding (c_1 choose 1) +
// (c_2 choose 2) + ... + (c_k choose k)
// NOTE: combination values are assumed to start from zero, so
// a combination like {1, 2, 3, 4, 5} will give a non-zero result
// ----------------------------------------------------------------------
public static int combination_2_index(int[] combo) {
int ix = 0, i = 1;
Array.Sort(combo);
foreach (int c in combo) {
if (c > 0) ix += binomial(c, i);
i++;
}
return ix;
}
// The reverse of this process is a bit fiddly. See Wikipedia for an
// explanation: https://e...content-available-to-author-only...a.org/wiki/Combinatorial_number_system
// ----------------------------------------------------------------------
public static int[] index_2_combination(int ix, int k) {
List<int> combo_list = new List<int>();
while (k >= 1) {
int n = k - 1;
if (ix == 0) {
combo_list.Add(n);
k--;
continue;
}
int b = 0;
while (true) {
// (Using a linear search here, but a binary search with
// precomputed binomial values would be faster)
int b0 = b;
b = binomial(n, k);
if (b > ix || ix == 0) {
ix -= b0;
combo_list.Add(n-1);
break;
}
n++;
}
k--;
}
int[] combo = combo_list.ToArray();
Array.Sort(combo);
return combo;
}
public static void Main()
{
int[][] test_combos = new int[][] {
new int[] {0,1,2,3,4,5},
new int[] {0,1,2,3,4,6},
new int[] {38,40,41,42,43,44},
new int[] {39,40,41,42,43,44}
};
int ix;
for (int i=0; i<test_combos.Length; i++) {
ix = combination_2_index(test_combos[i]);
int[] combo = index_2_combination(ix, test_combos[i].Length);
Console.WriteLine("{0} -> [{1}]", ix, string.Join(", ", combo));
}
}
}
dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uTnVtZXJpY3M7CnVzaW5nIFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljOwoKcHVibGljIGNsYXNzIFRlc3QKewogICAgLy8gSGVscGVyIGZ1bmN0aW9ucyBmb3IgY2FsY3VsYXRpbmcgdmFsdWVzIG9mIChuIGNob29zZSBrKS4KICAgIC8vIFRoZXNlIGFyZSBub3Qgb3B0aW1hbGx5IGNvZGVkIQoJLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoJcHJvdGVjdGVkIHN0YXRpYyBCaWdJbnRlZ2VyIGZhY3RvcmlhbChpbnQgbikgewoJCUJpZ0ludGVnZXIgZiA9IDE7CgkJd2hpbGUgKG4gPiAxKSBmICo9IG4tLTsKCQlyZXR1cm4gZjsKCX0KCQoJcHJvdGVjdGVkIHN0YXRpYyBpbnQgYmlub21pYWwoaW50IG4sIGludCBrKSB7CgkJaWYgKGsgPiBuKSByZXR1cm4gMDsKCQlyZXR1cm4gKGludCkoZmFjdG9yaWFsKG4pIC8gKGZhY3RvcmlhbChrKSAqIGZhY3RvcmlhbChuLWspKSk7Cgl9CgkKCS8vIEluIHRoZSBjb21iaW5hdG9yaWFsIG51bWJlciBzeXN0ZW0sIGEgY29tYmluYXRpb24ge2NfMSwgY18yLCAuLi4sIGNfa30KCS8vIGNvcnJlc3BvbmRzIHRvIHRoZSBpbnRlZ2VyIHZhbHVlIG9idGFpbmVkIGJ5IGFkZGluZyAoY18xIGNob29zZSAxKSArCgkvLyAoY18yIGNob29zZSAyKSArIC4uLiArIChjX2sgY2hvb3NlIGspCgkvLyBOT1RFOiBjb21iaW5hdGlvbiB2YWx1ZXMgYXJlIGFzc3VtZWQgdG8gc3RhcnQgZnJvbSB6ZXJvLCBzbwoJLy8gYSBjb21iaW5hdGlvbiBsaWtlIHsxLCAyLCAzLCA0LCA1fSB3aWxsIGdpdmUgYSBub24temVybyByZXN1bHQKCS8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCXB1YmxpYyBzdGF0aWMgaW50IGNvbWJpbmF0aW9uXzJfaW5kZXgoaW50W10gY29tYm8pIHsKCQlpbnQgaXggPSAwLCBpID0gMTsKCQlBcnJheS5Tb3J0KGNvbWJvKTsKCQlmb3JlYWNoIChpbnQgYyBpbiBjb21ibykgewoJCQlpZiAoYyA+IDApIGl4ICs9IGJpbm9taWFsKGMsIGkpOwoJCQlpKys7CgkJfQoJCXJldHVybiBpeDsKCX0KCQoJLy8gVGhlIHJldmVyc2Ugb2YgdGhpcyBwcm9jZXNzIGlzIGEgYml0IGZpZGRseS4gU2VlIFdpa2lwZWRpYSBmb3IgYW4KCS8vIGV4cGxhbmF0aW9uOiBodHRwczovL2UuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmEub3JnL3dpa2kvQ29tYmluYXRvcmlhbF9udW1iZXJfc3lzdGVtCgkvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCglwdWJsaWMgc3RhdGljIGludFtdIGluZGV4XzJfY29tYmluYXRpb24oaW50IGl4LCBpbnQgaykgewoJCUxpc3Q8aW50PiBjb21ib19saXN0ID0gbmV3IExpc3Q8aW50PigpOwoJCXdoaWxlIChrID49IDEpIHsKCQkJaW50IG4gPSBrIC0gMTsKCQkJaWYgKGl4ID09IDApIHsKCQkJCWNvbWJvX2xpc3QuQWRkKG4pOwoJCQkJay0tOwoJCQkJY29udGludWU7CgkJCX0KCQkJaW50IGIgPSAwOwoJCQl3aGlsZSAodHJ1ZSkgewoJCQkgICAgLy8gKFVzaW5nIGEgbGluZWFyIHNlYXJjaCBoZXJlLCBidXQgYSBiaW5hcnkgc2VhcmNoIHdpdGgKCQkJICAgIC8vIHByZWNvbXB1dGVkIGJpbm9taWFsIHZhbHVlcyB3b3VsZCBiZSBmYXN0ZXIpCgkJCQlpbnQgYjAgPSBiOwoJCQkJYiA9IGJpbm9taWFsKG4sIGspOwoJCQkJaWYgKGIgPiBpeCB8fCBpeCA9PSAwKSB7CgkJCQkJaXggLT0gYjA7CgkJCQkJY29tYm9fbGlzdC5BZGQobi0xKTsKCQkJCQlicmVhazsKCQkJCX0KCQkJCW4rKzsKCQkJfQoJCQlrLS07CgkJfQoJCWludFtdIGNvbWJvID0gY29tYm9fbGlzdC5Ub0FycmF5KCk7CgkJQXJyYXkuU29ydChjb21ibyk7CgkJcmV0dXJuIGNvbWJvOwoJfQoJCglwdWJsaWMgc3RhdGljIHZvaWQgTWFpbigpCgl7CgkJaW50W11bXSB0ZXN0X2NvbWJvcyA9IG5ldyBpbnRbXVtdIHsKCQkgICAgbmV3IGludFtdIHswLDEsMiwzLDQsNX0sCgkJICAgIG5ldyBpbnRbXSB7MCwxLDIsMyw0LDZ9LAoJCSAgICBuZXcgaW50W10gezM4LDQwLDQxLDQyLDQzLDQ0fSwKCQkgICAgbmV3IGludFtdIHszOSw0MCw0MSw0Miw0Myw0NH0KCQl9OwoJCWludCBpeDsKCQlmb3IgKGludCBpPTA7IGk8dGVzdF9jb21ib3MuTGVuZ3RoOyBpKyspIHsKCQkJaXggPSBjb21iaW5hdGlvbl8yX2luZGV4KHRlc3RfY29tYm9zW2ldKTsKCQkJaW50W10gY29tYm8gPSBpbmRleF8yX2NvbWJpbmF0aW9uKGl4LCB0ZXN0X2NvbWJvc1tpXS5MZW5ndGgpOwoJCQlDb25zb2xlLldyaXRlTGluZSgiezB9IC0+IFt7MX1dIiwgaXgsIHN0cmluZy5Kb2luKCIsICIsIGNvbWJvKSk7CgkJfQoJfQp9Cg==