#include <stdio.h>
#include <malloc.h>
#include <math.h>
#include <limits.h>
#include <stdlib.h>
#include <time.h>
struct Set
{
int n; /* number of elements in the set */
int min; /* minimum distance between elements of this set */
int best; /* best minimum distance for all sets up to this set */
};
/* Set sizes */
struct Set sets[] = {
{ 19 },
{ 19 },
{ 18 },
{ 16 },
{ 16 },
{ 14 },
{ 11 },
{ 11 },
{ 11 },
{ 9 },
{ 9 },
{ 7 },
{ 7 },
{ 7 },
{ 6 },
{ 5 },
{ 4 },
{ 3 },
{ 2 },
{ 2 },
};
#define Singles 6 /* number of one-element sets */
#define RT_BEGIN 10. /* starting reciprocal "temperature" */
#define RT_END 1000. /* ending reciprocal "temperature" */
#define RT_STEP 3.0e-5 /* speed of "temperature" change */
#define RT_FINE_STEP 1.0e-5 /* speed of "temperature" change on final step*/
#define IMPROVE_LIMIT 0.5/*portion of array values with harder qality function*/
#define SRAND 1 /* randomize */
#define SKIP_GROUPS 0 /* perform simulated annealing only once */
#define M (sizeof(sets) / sizeof(struct Set))
#define SinglesSet (-1)
#define INF INT_MAX
#define SWAP(a, b) { struct A t = a; a = b; b = t; }
struct A
{
int set; /* set number */
int l; /* distance to the nearest element of the same set to the left */
int r; /* distance to the nearest element of the same set to the right */
};
struct Align
{
struct A* a; /* array */
double* l; /* pre-computed table of logarithms */
int* m; /* histograms of distances */
int n; /* number of elements in the array */
int nn; /* number of elements in largest sets */
int bestMin; /* optimal min.distance for largest sets */
int startVar; /* number of largest sets */
int startWatch; /* start of not-yet optimized portion of sets */
};
/* Quality function */
static double eval(double* l, int n, int x)
{
++x;
if (x > 0)
{
return (x >= n)? 0: l[x];
}
else
{
return -(1 << (1 - x));
}
}
/* Calculates how much quality may be improved after swapping elements
left and left+1 */
static double compare(struct Align* a, int left)
{
double result = 0.;
int right = left + 1;
if (a->a[left].set != SinglesSet)
{
int best = sets[a->a[left].set].best;
result +=
eval(a->l, a->n, a->a[left].l + 1 - best) -
eval(a->l, a->n, a->a[left].l - best) +
eval(a->l, a->n, a->a[left].r - 1 - best) -
eval(a->l, a->n, a->a[left].r - best);
}
if (a->a[right].set != SinglesSet)
{
int best = sets[a->a[right].set].best;
result +=
eval(a->l, a->n, a->a[right].l - 1 - best) -
eval(a->l, a->n, a->a[right].l - best) +
eval(a->l, a->n, a->a[right].r + 1 - best) -
eval(a->l, a->n, a->a[right].r - best);
}
return result;
}
/* Harden quality function for not-yet-optimized portion of sets if possible */
static void improve(struct Align* a)
{
int i;
for (i = 0; i < a->startWatch; ++i)
{
if (sets[i].min < sets[i].best)
return;
}
for (i = a->startWatch; i < M; ++i)
{
if (sets[i].min <= sets[i].best)
return;
}
for (i = a->startWatch; i < M; ++i)
{
++sets[i].best;
}
}
/* Update distances for one of the swapped elements,
update minimal distance for correspondent set */
static void
update(struct Align* a, int* d, int theSet, int pos, int diff, int lr)
{
int better = 0;
--a->m[a->n * theSet + *d];
if (sets[theSet].min == *d &&
a->m[a->n * theSet + *d] == 0)
{
sets[theSet].min += diff;
better = (diff == 1)? 1: 0;
}
*d += diff;
pos += *d * diff * lr * -1;
++a->m[a->n * theSet + *d];
if (*d == sets[theSet].min - 1)
{
sets[theSet].min = *d;
}
if (diff * lr == 1) /* left */
{
a->a[pos].r += diff;
}
else /* right */
{
a->a[pos].l += diff;
}
if (better)
{
improve(a);
}
}
/* Swap elements left and left+1 */
static void swap(struct Align* a, int left)
{
int right = left + 1;
SWAP(a->a[left], a->a[right])
if (a->a[left].l < a->n)
update(a, &(a->a[left].l), a->a[left].set, left, -1, -1);
if (a->a[right].r < a->n)
update(a, &(a->a[right].r), a->a[right].set, right, -1, 1);
if (a->a[left].r < a->n)
update(a, &(a->a[left].r), a->a[left].set, left, 1, -1);
if (a->a[right].l < a->n)
update(a, &(a->a[right].l), a->a[right].set, right, 1, 1);
}
/* Main loop of simulated annealing */
static void iterate(struct Align* a, double step)
{
int i;
double rt = RT_BEGIN;
while (rt < RT_END)
{
/*printf("\nrt=%g\n", rt);*/
for (i = 0; i != a->n; ++i)
{
double d;
int left;
do {
left
= rand() % (a
->n
- 1); } while (a->a[left].set == a->a[left+1].set);
d = compare(a, left);
if (d
>= 0.
|| exp(d
* rt
) * RAND_MAX
> rand()) {
swap(a, left);
}
}
rt *= 1.0 + step;
}
}
/* Perform simulated annealing for equally-sized groups of sets,
which allows to incrementally tighten quality function for these groups */
static void groups(struct Align* a)
{
for (a->startWatch = a->startVar; a->startWatch < M;)
{
int oldN = sets[a->startWatch].n;
iterate(a, RT_STEP);
#if SKIP_GROUPS
return;
#endif
for (; a->startWatch < M && sets[a->startWatch].n == oldN; ++a->startWatch)
{
a->nn += sets[a->startWatch].n;
if (a->nn > a->n * IMPROVE_LIMIT)
{
}
}
}
iterate(a, RT_FINE_STEP);
}
/* Allocate memory, initialize everything */
static void setup()
{
int i;
int theSet = 0;
int theSetElems = sets[theSet].n;
struct Align a;
a.a = 0;
a.l = 0;
a.m = 0;
a.n = Singles;
a.startVar = 0;
for (i = 0; i < M; ++i)
{
a.n += sets[i].n;
if (!a.startVar && sets[i].n != sets[0].n)
{
a.startVar = i;
}
if (!a.startVar)
{
a.nn += sets[i].n;
}
}
a.
a = calloc(a.
n, sizeof(struct A
)); a.
l = calloc(a.
n, sizeof(double)); a.
m = calloc(a.
n, M
* sizeof(int));
for (i = 1; i < a.n; ++i)
{
}
a.bestMin = (a.n - a.startVar) / (sets[0].n - 1);
i = 0;
while (1)
{
a.a[i].set = theSet;
a.a[i].l = (theSetElems == sets[theSet].n)? INF: 1;
--theSetElems;
a.a[i].r = theSetElems? 1: INF;
++i;
if (!theSetElems)
{
sets[theSet].min = 1;
sets[theSet].best = a.bestMin;
a.m[a.n * theSet + 1] = sets[theSet].n - 1;
++theSet;
if (theSet == M)
break;
theSetElems = sets[theSet].n;
}
}
for (; i < a.n; ++i)
{
a.a[i].set = SinglesSet;
a.a[i].l = INF;
a.a[i].r = INF;
}
groups(&a);
/*for (i = 0; i < a.n; ++i)
{
printf("%d ", a.a[i].set);
}*/
}
int main()
{
#if SRAND
#endif
setup();
/* Print set size, minimal distance, limit for minimal distance */
int i;
for (i = 0; i < M; ++i)
{
printf("\n%d\t%d", sets
[i
].
n, sets
[i
].
min);
if (sets[i].best != sets[i].min)
{
}
}
return 0;
}
I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxtYWxsb2MuaD4KI2luY2x1ZGUgPG1hdGguaD4KI2luY2x1ZGUgPGxpbWl0cy5oPgojaW5jbHVkZSA8c3RkbGliLmg+CiNpbmNsdWRlIDx0aW1lLmg+CgpzdHJ1Y3QgU2V0CnsKICBpbnQgbjsgICAgLyogbnVtYmVyIG9mIGVsZW1lbnRzIGluIHRoZSBzZXQgKi8KICBpbnQgbWluOyAgLyogbWluaW11bSBkaXN0YW5jZSBiZXR3ZWVuIGVsZW1lbnRzIG9mIHRoaXMgc2V0ICovCiAgaW50IGJlc3Q7IC8qIGJlc3QgbWluaW11bSBkaXN0YW5jZSBmb3IgYWxsIHNldHMgdXAgdG8gdGhpcyBzZXQgKi8KfTsKCi8qIFNldCBzaXplcyAqLwpzdHJ1Y3QgU2V0IHNldHNbXSA9IHsKICB7IDE5IH0sCiAgeyAxOSB9LAogIHsgMTggfSwKICB7IDE2IH0sCiAgeyAxNiB9LAogIHsgMTQgfSwKICB7IDExIH0sCiAgeyAxMSB9LAogIHsgMTEgfSwKICB7IDkgfSwKICB7IDkgfSwKICB7IDcgfSwKICB7IDcgfSwKICB7IDcgfSwKICB7IDYgfSwKICB7IDUgfSwKICB7IDQgfSwKICB7IDMgfSwKICB7IDIgfSwKICB7IDIgfSwKfTsKI2RlZmluZSBTaW5nbGVzIDYgLyogbnVtYmVyIG9mIG9uZS1lbGVtZW50IHNldHMgKi8KCiNkZWZpbmUgUlRfQkVHSU4gMTAuICAgICAgICAvKiBzdGFydGluZyByZWNpcHJvY2FsICJ0ZW1wZXJhdHVyZSIgKi8KI2RlZmluZSBSVF9FTkQgMTAwMC4gICAgICAgIC8qIGVuZGluZyByZWNpcHJvY2FsICJ0ZW1wZXJhdHVyZSIgKi8KI2RlZmluZSBSVF9TVEVQIDMuMGUtNSAgICAgIC8qIHNwZWVkIG9mICJ0ZW1wZXJhdHVyZSIgY2hhbmdlICovCiNkZWZpbmUgUlRfRklORV9TVEVQIDEuMGUtNSAvKiBzcGVlZCBvZiAidGVtcGVyYXR1cmUiIGNoYW5nZSBvbiBmaW5hbCBzdGVwKi8KI2RlZmluZSBJTVBST1ZFX0xJTUlUIDAuNS8qcG9ydGlvbiBvZiBhcnJheSB2YWx1ZXMgd2l0aCBoYXJkZXIgcWFsaXR5IGZ1bmN0aW9uKi8KI2RlZmluZSBTUkFORCAxICAgICAgICAgICAgIC8qIHJhbmRvbWl6ZSAqLwojZGVmaW5lIFNLSVBfR1JPVVBTIDAgICAgICAgLyogcGVyZm9ybSBzaW11bGF0ZWQgYW5uZWFsaW5nIG9ubHkgb25jZSAqLwoKI2RlZmluZSBNIChzaXplb2Yoc2V0cykgLyBzaXplb2Yoc3RydWN0IFNldCkpCiNkZWZpbmUgU2luZ2xlc1NldCAoLTEpCiNkZWZpbmUgSU5GIElOVF9NQVgKCiNkZWZpbmUgU1dBUChhLCBiKSB7IHN0cnVjdCBBIHQgPSBhOyBhID0gYjsgYiA9IHQ7IH0KCnN0cnVjdCBBCnsKICBpbnQgc2V0OyAvKiBzZXQgbnVtYmVyICovCiAgaW50IGw7ICAgLyogZGlzdGFuY2UgdG8gdGhlIG5lYXJlc3QgZWxlbWVudCBvZiB0aGUgc2FtZSBzZXQgdG8gdGhlIGxlZnQgKi8KICBpbnQgcjsgICAvKiBkaXN0YW5jZSB0byB0aGUgbmVhcmVzdCBlbGVtZW50IG9mIHRoZSBzYW1lIHNldCB0byB0aGUgcmlnaHQgKi8KfTsKCnN0cnVjdCBBbGlnbgp7CiAgc3RydWN0IEEqIGE7ICAgIC8qIGFycmF5ICovCiAgZG91YmxlKiBsOyAgICAgIC8qIHByZS1jb21wdXRlZCB0YWJsZSBvZiBsb2dhcml0aG1zICovCiAgaW50KiBtOyAgICAgICAgIC8qIGhpc3RvZ3JhbXMgb2YgZGlzdGFuY2VzICovCiAgaW50IG47ICAgICAgICAgIC8qIG51bWJlciBvZiBlbGVtZW50cyBpbiB0aGUgYXJyYXkgKi8KICBpbnQgbm47ICAgICAgICAgLyogbnVtYmVyIG9mIGVsZW1lbnRzIGluIGxhcmdlc3Qgc2V0cyAqLwogIGludCBiZXN0TWluOyAgICAvKiBvcHRpbWFsIG1pbi5kaXN0YW5jZSBmb3IgbGFyZ2VzdCBzZXRzICovCiAgaW50IHN0YXJ0VmFyOyAgIC8qIG51bWJlciBvZiBsYXJnZXN0IHNldHMgKi8KICBpbnQgc3RhcnRXYXRjaDsgLyogc3RhcnQgb2Ygbm90LXlldCBvcHRpbWl6ZWQgcG9ydGlvbiBvZiBzZXRzICovCn07CgovKiBRdWFsaXR5IGZ1bmN0aW9uICovCnN0YXRpYyBkb3VibGUgZXZhbChkb3VibGUqIGwsIGludCBuLCBpbnQgeCkKewogICsreDsKCiAgaWYgKHggPiAwKQogIHsKICAgIHJldHVybiAoeCA+PSBuKT8gMDogbFt4XTsKICB9CiAgZWxzZQogIHsKICAgIHJldHVybiAtKDEgPDwgKDEgLSB4KSk7CiAgfQp9CgovKiBDYWxjdWxhdGVzIGhvdyBtdWNoIHF1YWxpdHkgbWF5IGJlIGltcHJvdmVkIGFmdGVyIHN3YXBwaW5nIGVsZW1lbnRzCiAgIGxlZnQgYW5kIGxlZnQrMSAqLwpzdGF0aWMgZG91YmxlIGNvbXBhcmUoc3RydWN0IEFsaWduKiBhLCBpbnQgbGVmdCkKewogIGRvdWJsZSByZXN1bHQgPSAwLjsKICBpbnQgcmlnaHQgPSBsZWZ0ICsgMTsKCiAgaWYgKGEtPmFbbGVmdF0uc2V0ICE9IFNpbmdsZXNTZXQpCiAgewogICAgaW50IGJlc3QgPSBzZXRzW2EtPmFbbGVmdF0uc2V0XS5iZXN0OwoKICAgIHJlc3VsdCArPQogICAgICBldmFsKGEtPmwsIGEtPm4sIGEtPmFbbGVmdF0ubCArIDEgLSBiZXN0KSAtCiAgICAgIGV2YWwoYS0+bCwgYS0+biwgYS0+YVtsZWZ0XS5sIC0gYmVzdCkgKwogICAgICBldmFsKGEtPmwsIGEtPm4sIGEtPmFbbGVmdF0uciAtIDEgLSBiZXN0KSAtCiAgICAgIGV2YWwoYS0+bCwgYS0+biwgYS0+YVtsZWZ0XS5yIC0gYmVzdCk7CiAgfQoKICBpZiAoYS0+YVtyaWdodF0uc2V0ICE9IFNpbmdsZXNTZXQpCiAgewogICAgaW50IGJlc3QgPSBzZXRzW2EtPmFbcmlnaHRdLnNldF0uYmVzdDsKCiAgICByZXN1bHQgKz0KICAgICAgZXZhbChhLT5sLCBhLT5uLCBhLT5hW3JpZ2h0XS5sIC0gMSAtIGJlc3QpIC0KICAgICAgZXZhbChhLT5sLCBhLT5uLCBhLT5hW3JpZ2h0XS5sIC0gYmVzdCkgKwogICAgICBldmFsKGEtPmwsIGEtPm4sIGEtPmFbcmlnaHRdLnIgKyAxIC0gYmVzdCkgLQogICAgICBldmFsKGEtPmwsIGEtPm4sIGEtPmFbcmlnaHRdLnIgLSBiZXN0KTsKICB9CgogIHJldHVybiByZXN1bHQ7Cn0KCi8qIEhhcmRlbiBxdWFsaXR5IGZ1bmN0aW9uIGZvciBub3QteWV0LW9wdGltaXplZCBwb3J0aW9uIG9mIHNldHMgaWYgcG9zc2libGUgKi8Kc3RhdGljIHZvaWQgaW1wcm92ZShzdHJ1Y3QgQWxpZ24qIGEpCnsKICBpbnQgaTsKICBmb3IgKGkgPSAwOyBpIDwgYS0+c3RhcnRXYXRjaDsgKytpKQogIHsKICAgIGlmIChzZXRzW2ldLm1pbiA8IHNldHNbaV0uYmVzdCkKICAgICAgcmV0dXJuOwogIH0KCiAgZm9yIChpID0gYS0+c3RhcnRXYXRjaDsgaSA8IE07ICsraSkKICB7CiAgICBpZiAoc2V0c1tpXS5taW4gPD0gc2V0c1tpXS5iZXN0KQogICAgICByZXR1cm47CiAgfQoKICBmb3IgKGkgPSBhLT5zdGFydFdhdGNoOyBpIDwgTTsgKytpKQogIHsKICAgICsrc2V0c1tpXS5iZXN0OwogIH0KfQoKLyogVXBkYXRlIGRpc3RhbmNlcyBmb3Igb25lIG9mIHRoZSBzd2FwcGVkIGVsZW1lbnRzLAogIHVwZGF0ZSBtaW5pbWFsIGRpc3RhbmNlIGZvciBjb3JyZXNwb25kZW50IHNldCAqLwpzdGF0aWMgdm9pZAp1cGRhdGUoc3RydWN0IEFsaWduKiBhLCBpbnQqIGQsIGludCB0aGVTZXQsIGludCBwb3MsIGludCBkaWZmLCBpbnQgbHIpCnsKICBpbnQgYmV0dGVyID0gMDsKICAtLWEtPm1bYS0+biAqIHRoZVNldCArICpkXTsKCiAgaWYgKHNldHNbdGhlU2V0XS5taW4gPT0gKmQgJiYKICAgICAgYS0+bVthLT5uICogdGhlU2V0ICsgKmRdID09IDApCiAgewogICAgc2V0c1t0aGVTZXRdLm1pbiArPSBkaWZmOwogICAgYmV0dGVyID0gKGRpZmYgPT0gMSk/IDE6IDA7CiAgfQoKICAqZCArPSBkaWZmOwogIHBvcyArPSAqZCAqIGRpZmYgKiBsciAqIC0xOwogICsrYS0+bVthLT5uICogdGhlU2V0ICsgKmRdOwoKICBpZiAoKmQgPT0gc2V0c1t0aGVTZXRdLm1pbiAtIDEpCiAgewogICAgc2V0c1t0aGVTZXRdLm1pbiA9ICpkOwogIH0KCiAgaWYgKGRpZmYgKiBsciA9PSAxKSAvKiBsZWZ0ICovCiAgewogICAgYS0+YVtwb3NdLnIgKz0gZGlmZjsKICB9CiAgZWxzZSAvKiByaWdodCAqLwogIHsKICAgIGEtPmFbcG9zXS5sICs9IGRpZmY7CiAgfQoKICBpZiAoYmV0dGVyKQogIHsKICAgIGltcHJvdmUoYSk7CiAgfQp9CgovKiBTd2FwIGVsZW1lbnRzIGxlZnQgYW5kIGxlZnQrMSAqLwpzdGF0aWMgdm9pZCBzd2FwKHN0cnVjdCBBbGlnbiogYSwgaW50IGxlZnQpCnsKICBpbnQgcmlnaHQgPSBsZWZ0ICsgMTsKICBTV0FQKGEtPmFbbGVmdF0sIGEtPmFbcmlnaHRdKQoKICBpZiAoYS0+YVtsZWZ0XS5sIDwgYS0+bikKICAgIHVwZGF0ZShhLCAmKGEtPmFbbGVmdF0ubCksIGEtPmFbbGVmdF0uc2V0LCBsZWZ0LCAtMSwgLTEpOwoKICBpZiAoYS0+YVtyaWdodF0uciA8IGEtPm4pCiAgICB1cGRhdGUoYSwgJihhLT5hW3JpZ2h0XS5yKSwgYS0+YVtyaWdodF0uc2V0LCByaWdodCwgLTEsIDEpOwoKICBpZiAoYS0+YVtsZWZ0XS5yIDwgYS0+bikKICAgIHVwZGF0ZShhLCAmKGEtPmFbbGVmdF0uciksIGEtPmFbbGVmdF0uc2V0LCBsZWZ0LCAxLCAtMSk7CgogIGlmIChhLT5hW3JpZ2h0XS5sIDwgYS0+bikKICAgIHVwZGF0ZShhLCAmKGEtPmFbcmlnaHRdLmwpLCBhLT5hW3JpZ2h0XS5zZXQsIHJpZ2h0LCAxLCAxKTsKfQoKLyogTWFpbiBsb29wIG9mIHNpbXVsYXRlZCBhbm5lYWxpbmcgKi8Kc3RhdGljIHZvaWQgaXRlcmF0ZShzdHJ1Y3QgQWxpZ24qIGEsIGRvdWJsZSBzdGVwKQp7CiAgaW50IGk7CiAgZG91YmxlIHJ0ID0gUlRfQkVHSU47CgogIHdoaWxlIChydCA8IFJUX0VORCkKICB7CiAgICAvKnByaW50ZigiXG5ydD0lZ1xuIiwgcnQpOyovCgogICAgZm9yIChpID0gMDsgaSAhPSBhLT5uOyArK2kpCiAgICB7CiAgICAgIGRvdWJsZSBkOwogICAgICBpbnQgbGVmdDsKCiAgICAgIGRvIHsKCWxlZnQgID0gcmFuZCgpICUgKGEtPm4gLSAxKTsKICAgICAgfSB3aGlsZSAoYS0+YVtsZWZ0XS5zZXQgPT0gYS0+YVtsZWZ0KzFdLnNldCk7CgogICAgICBkID0gY29tcGFyZShhLCBsZWZ0KTsKCiAgICAgIGlmIChkID49IDAuIHx8IGV4cChkICogcnQpICogUkFORF9NQVggPiByYW5kKCkpCiAgICAgIHsKCXN3YXAoYSwgbGVmdCk7CiAgICAgIH0KICAgIH0KCiAgICBydCAqPSAxLjAgKyBzdGVwOwogIH0KfQoKLyogUGVyZm9ybSBzaW11bGF0ZWQgYW5uZWFsaW5nIGZvciBlcXVhbGx5LXNpemVkIGdyb3VwcyBvZiBzZXRzLAogIHdoaWNoIGFsbG93cyB0byBpbmNyZW1lbnRhbGx5IHRpZ2h0ZW4gcXVhbGl0eSBmdW5jdGlvbiBmb3IgdGhlc2UgZ3JvdXBzICovCnN0YXRpYyB2b2lkIGdyb3VwcyhzdHJ1Y3QgQWxpZ24qIGEpCnsKICBmb3IgKGEtPnN0YXJ0V2F0Y2ggPSBhLT5zdGFydFZhcjsgYS0+c3RhcnRXYXRjaCA8IE07KQogIHsKICAgIGludCBvbGROID0gc2V0c1thLT5zdGFydFdhdGNoXS5uOwogICAgaXRlcmF0ZShhLCBSVF9TVEVQKTsKCiNpZiBTS0lQX0dST1VQUwogICAgcmV0dXJuOwojZW5kaWYKCiAgICBmb3IgKDsgYS0+c3RhcnRXYXRjaCA8IE0gJiYgc2V0c1thLT5zdGFydFdhdGNoXS5uID09IG9sZE47ICsrYS0+c3RhcnRXYXRjaCkKICAgIHsKICAgICAgYS0+bm4gKz0gc2V0c1thLT5zdGFydFdhdGNoXS5uOwoKICAgICAgaWYgKGEtPm5uID4gYS0+biAqIElNUFJPVkVfTElNSVQpCiAgICAgIHsKCWdvdG8gZXhpdDsKICAgICAgfQogICAgfQogIH0KCiBleGl0OgogIGl0ZXJhdGUoYSwgUlRfRklORV9TVEVQKTsKfQoKLyogQWxsb2NhdGUgbWVtb3J5LCBpbml0aWFsaXplIGV2ZXJ5dGhpbmcgKi8Kc3RhdGljIHZvaWQgc2V0dXAoKQp7CiAgaW50IGk7CiAgaW50IHRoZVNldCA9IDA7CiAgaW50IHRoZVNldEVsZW1zID0gc2V0c1t0aGVTZXRdLm47CiAgc3RydWN0IEFsaWduIGE7CgogIGEuYSA9IDA7CiAgYS5sID0gMDsKICBhLm0gPSAwOwogIGEubiA9IFNpbmdsZXM7CiAgYS5zdGFydFZhciA9IDA7CgogIGZvciAoaSA9IDA7IGkgPCBNOyArK2kpCiAgewogICAgYS5uICs9IHNldHNbaV0ubjsKCiAgICBpZiAoIWEuc3RhcnRWYXIgJiYgc2V0c1tpXS5uICE9IHNldHNbMF0ubikKICAgIHsKICAgICAgYS5zdGFydFZhciA9IGk7CiAgICB9CgogICAgaWYgKCFhLnN0YXJ0VmFyKQogICAgewogICAgICBhLm5uICs9IHNldHNbaV0ubjsKICAgIH0KICB9CgogIGEuYSA9IGNhbGxvYyhhLm4sIHNpemVvZihzdHJ1Y3QgQSkpOwogIGEubCA9IGNhbGxvYyhhLm4sIHNpemVvZihkb3VibGUpKTsKICBhLm0gPSBjYWxsb2MoYS5uLCBNICogc2l6ZW9mKGludCkpOwoKICBmb3IgKGkgPSAxOyBpIDwgYS5uOyArK2kpCiAgewogICAgYS5sW2ldID0gbG9nKGkpOwogIH0KCiAgYS5iZXN0TWluID0gKGEubiAtIGEuc3RhcnRWYXIpIC8gKHNldHNbMF0ubiAtIDEpOwogIGkgPSAwOwogIHdoaWxlICgxKQogIHsKICAgIGEuYVtpXS5zZXQgPSB0aGVTZXQ7CiAgICBhLmFbaV0ubCA9ICh0aGVTZXRFbGVtcyA9PSBzZXRzW3RoZVNldF0ubik/IElORjogMTsKICAgIC0tdGhlU2V0RWxlbXM7CiAgICBhLmFbaV0uciA9IHRoZVNldEVsZW1zPyAxOiBJTkY7CiAgICArK2k7CgogICAgaWYgKCF0aGVTZXRFbGVtcykKICAgIHsKICAgICAgc2V0c1t0aGVTZXRdLm1pbiA9IDE7CiAgICAgIHNldHNbdGhlU2V0XS5iZXN0ID0gYS5iZXN0TWluOwogICAgICBhLm1bYS5uICogdGhlU2V0ICsgMV0gPSBzZXRzW3RoZVNldF0ubiAtIDE7CiAgICAgICsrdGhlU2V0OwoKICAgICAgaWYgKHRoZVNldCA9PSBNKQoJYnJlYWs7CgogICAgICB0aGVTZXRFbGVtcyA9IHNldHNbdGhlU2V0XS5uOwogICAgfQogIH0KICBmb3IgKDsgaSA8IGEubjsgKytpKQogIHsKICAgIGEuYVtpXS5zZXQgPSBTaW5nbGVzU2V0OwogICAgYS5hW2ldLmwgPSBJTkY7CiAgICBhLmFbaV0uciA9IElORjsKICB9CgogIGdyb3VwcygmYSk7CgogIC8qZm9yIChpID0gMDsgaSA8IGEubjsgKytpKQogIHsKICAgIHByaW50ZigiJWQgIiwgYS5hW2ldLnNldCk7CiAgfSovCgogIGZyZWUoYS5tKTsKICBmcmVlKGEubCk7CiAgZnJlZShhLmEpOwp9CgppbnQgbWFpbigpCnsKI2lmIFNSQU5ECiAgc3JhbmQodGltZSgwKSk7CiNlbmRpZgoKICBzZXR1cCgpOwoKICAvKiBQcmludCBzZXQgc2l6ZSwgbWluaW1hbCBkaXN0YW5jZSwgbGltaXQgZm9yIG1pbmltYWwgZGlzdGFuY2UgKi8KICBpbnQgaTsKICBmb3IgKGkgPSAwOyBpIDwgTTsgKytpKQogIHsKICAgIHByaW50ZigiXG4lZFx0JWQiLCBzZXRzW2ldLm4sIHNldHNbaV0ubWluKTsKCiAgICBpZiAoc2V0c1tpXS5iZXN0ICE9IHNldHNbaV0ubWluKQogICAgewogICAgICBwcmludGYoIlx0JWQiLCBzZXRzW2ldLmJlc3QpOwogICAgfQogIH0KICBwdXRzKCJcbiIpOwoKICByZXR1cm4gMDsKfQo=