#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
const uint32_t RADIX = 10000;
const double pi = 3.1415926535897932385;
double cos1;
double sin1;
void fr(double *s1,double *s2,double *end,size_t add,size_t t90){
for(;s1<end;s1+=add,s2+=add){
double r0,r1,r2,r3,m0,m1;
r0=s1[0];
r1=s2[0];
r2=s1[t90];
r3=s2[t90];
m0=r2*cos1-r3*sin1;
m1=r2*sin1+r3*cos1;
s1[0] = r0+m0;
s2[0] = r0-m0;
s1[t90] =-r1+m1;
s2[t90] = r1+m1;
}
}
void fri(double *s1,double *s2,double *end,size_t add,size_t t90){
for(;s1<end;s1+=add,s2+=add){
double r0,r1,r2,r3,m0,m1,m2,m3;
r0=s1[0];
r1=s2[0];
r2=s1[t90];
r3=s2[t90];
m0= r0+r1;
m1=-r2+r3;
m2= r0-r1;
m3= r2+r3;
s1[0] = m0;
s2[0] = m1;
s1[t90] = m2*cos1+m3*sin1;
s2[t90] =-m2*sin1+m3*cos1;
}
}
void fr0(double *s1,double *end,size_t add,size_t t90){
for(;s1<end;s1+=add){
double r0,r1;
r0=s1[0];
r1=s1[t90];
s1[0] =r0+r1;
s1[t90] =r0-r1;
}
}
void swap_d(double *a, double *b) {
double t = *a;
*a = *b;
*b = t;
}
void bxchg(double *s,int p){
size_t t4, t5, t6;
size_t t045, t090, t180, t270;
t045 = (size_t)1<<p-3;
t090 = t045 + t045;
t180 = t090 + t090;
t270 = t180 + t090;
t4 = t090 - 4;
t5 = t4;
do {
swap_d(&s[t4+1], &s[t180+t5]);
swap_d(&s[t4+2], &s[t090+t5]);
swap_d(&s[t4+3], &s[t270+t5]);
swap_d(&s[t090+t4+1], &s[t180+t5+2]);
swap_d(&s[t090+t4+3], &s[t270+t5+2]);
swap_d(&s[t180+t4+3], &s[t270+t5+1]);
if(t4 < t5){
swap_d(&s[t4], &s[t5]);
swap_d(&s[t090+t4+2], &s[t090+t5+2]);
swap_d(&s[t180+t4+1], &s[t180+t5+1]);
swap_d(&s[t270+t4+3], &s[t270+t5+3]);
}
if (t4 == 0){
break;
}
t4 -= 4;
t6 = t045;
for(;;){
t5 ^= t6;
if((t5 & t6) == 0){
break;
}
t6 >>= 1;
}
} while (1);
}
void bitexchg(double *s,int p){
if (p <= 1){
}
else if (p == 2){
swap_d(&s[1],&s[2]);
}
else if (p == 3){
swap_d(&s[1],&s[4]);
swap_d(&s[3],&s[6]);
}
else {
bxchg(s,p);
}
}
double* SIN_TABLE[64] = {0};
const double* sin_table(int p){
if (p >= 2 && SIN_TABLE[p] == 0){
size_t t090 = (size_t)1<<p-2;
SIN_TABLE[p] = (double*)malloc(t090*sizeof(double));
double k = 0.5 * pi / t090;
for (int i = 0 ; i < t090 ; i++){
SIN_TABLE[p][i] = sin(k * i);
}
}
return SIN_TABLE[p];
}
void fouri(double *s, int p){
const double* table = sin_table(p);
bitexchg(s,p);
size_t q = (size_t)1<<p;
for (int i = 1;i <= p; i++){
size_t r360 = (size_t)1<<i;
size_t r180 = r360 / 2;
size_t r090 = r180 / 2;
size_t k1 = 0;
size_t k2 = r180 - 1;
fr0(&s[0], &s[q], r360, r180);
k1 ++;
size_t t0 = (size_t)1<<p-i;
size_t t1 = ((size_t)1<<p-2) - t0;
size_t t2 = (size_t)1<<p-i;
for (;k1 < r090;k1 ++,k2 --){
sin1 = table[t0];
cos1 = table[t1];
fr(&s[k1], &s[k2], &s[q], r360, r180);
t0 += t2;
t1 -= t2;
}
}
}
void fouriinv(double *s, int p){
const double* table = sin_table(p);
size_t q = (size_t)1<<p;
for (int i = p;i >= 1; i--){
size_t r360 = (size_t)1<<i;
size_t r180 = r360 / 2;
size_t r090 = r180 / 2;
size_t k1 = 0;
size_t k2 = r180 - 1;
fr0(&s[0], &s[q], r360, r180);
k1 ++;
size_t t0 = (size_t)1<<p-i;
size_t t1 = ((size_t)1<<p-2) - t0;
size_t t2 = (size_t)1<<p-i;
for (;k1 < r090;k1 ++,k2 --){
sin1 = table[t0];
cos1 = table[t1];
fri(&s[k1], &s[k2], &s[q], r360, r180);
t0 += t2;
t1 -= t2;
}
}
bitexchg(s,p);
}
int s2p(uint64_t s) {
int i;
for (i = 0; i < 64; i++) {
if ((size_t)1 << i >= s) {
break;
}
}
return i;
}
typedef struct I_ {
uint16_t *data;
size_t capacity;
size_t size;
} I;
typedef struct F_ {
double *data;
size_t capacity;
int p;
} F;
void alloc_i(I *a, size_t cap){
a->data = (uint16_t*)malloc(cap * sizeof(uint16_t));
a->capacity = cap;
}
void free_i(I *a) {
free(a->data);
}
void alloc_f(F *a, int p) {
size_t cap = (size_t)1 << p;
a->data = (double*)malloc(cap * sizeof(double));
a->capacity = cap;
}
void free_f(F *a){
free(a->data);
}
void swap_i(I *a, I *b) {
I t = *a;
*a = *b;
*b = t;
}
void i2f(F *a, const I *b, int p){
size_t i;
size_t t360 = (size_t)1 << p;
a->p = p;
int carry = 0;
for (i = 0; i < b->size -1; i++){
int t = b->data[i] + carry;
if (t < (int)RADIX/2){
a->data[i] = t;
carry = 0;
}
else {
a->data[i] = (int)t - (int)RADIX;
carry = 1;
}
}
a->data[i++] = b->data[i] + carry;
for (; i < t360; i++) {
a->data[i] = 0.;
}
fouri(a->data, p);
}
void mul_f2i(I *a, const F *b, const F *c, F *d){
int p = b->p;
size_t t180 = (size_t)1 << p-1;
size_t t360 = t180 + t180;
size_t i;
int64_t carry;
size_t t;
size_t s;
d->data[0] = b->data[0] * c->data[0] * .5;
d->data[t180] = b->data[t180] * c->data[t180] * .5;
{
size_t k1 = 1;
size_t k2 = ((size_t)1<<p)-1;
size_t end = t180;
for (; k1 < end ; k1++,k2--){
double re = b->data[k1] * c->data[k1] - b->data[k2] * c->data[k2];
double im = b->data[k1] * c->data[k2] + b->data[k2] * c->data[k1];
d->data[k1] = re;
d->data[k2] = im;
}
}
fouriinv(d->data, p);
s = a->capacity < t360 ? a->capacity : t360;
carry = 0;
t = 1;
double k = ldexp(1., -p+1);
for (i = 0 ; i < s ; i++){
int64_t e = (int64_t)floor(d->data[i] * k + .5) + carry;
int16_t f;
carry = e / RADIX;
f = (int16_t)(e - carry * RADIX);
if (f < 0){
f += RADIX;
carry --;
}
a->data[i] = f;
if (f != 0) {
t = i + 1;
}
}
a->size = t;
}
void add_i(I *a, const I *b, const I *c) {
uint16_t carry = 0;
size_t i;
if (b->size > c->size){
const I *t = b;
b = c;
c = t;
}
for (i = 0; i < b->size; i++) {
uint16_t d = b->data[i] + c->data[i] + carry;
carry = 0;
if (d >= RADIX){
d -= RADIX;
carry ++;
}
a->data[i] = d;
}
for (; i < c->size; i++) {
uint16_t d = c->data[i] + carry;
carry = 0;
if (d >= RADIX){
d -= RADIX;
carry ++;
}
a->data[i] = d;
}
a->size = c->size;
if (carry != 0){
a->data[a->size++] = carry;
}
}
void print(const I *a){
size_t s = a->size;
printf("%u", a->data[--s]);
while (s != 0) {
printf("%04u", a->data[--s]);
}
}
void f(uint64_t n){
I a, b, c;
F x, y, z;
int i, p;
{
size_t cap = (size_t)floor((log(sqrt(1.25) + .5)*n - 0.5*log(5.)) * (1. / log((double)RADIX)) + 2.001);
if (cap <= 2) {
cap = 2;
}
p = s2p(cap);
alloc_i(&a, cap);
alloc_i(&b, cap);
alloc_i(&c, cap);
alloc_f(&x, p);
alloc_f(&y, p);
alloc_f(&z, p);
a.data[0] = 1;
a.size = 1;
b.data[0] = 0;
b.size = 1;
}
for (i = 63; i > 0; i--) {
p = s2p(b.size + b.size);
i2f(&x, &a, p);
i2f(&y, &b, p);
mul_f2i(&c, &y, &y, &z);
mul_f2i(&a, &x, &x, &z);
add_i(&a, &a, &c);
mul_f2i(&b, &x, &y, &z);
add_i(&b, &b, &b);
add_i(&b, &b, &c);
if (n+1 & (size_t)1 << i) {
add_i(&a, &a, &b);
swap_i(&a, &b);
}
}
if (n+1 & 1) {
add_i(&a, &a, &a);
add_i(&a, &a, &b);
p = s2p(a.size + b.size);
i2f(&x, &a, p);
i2f(&y, &b, p);
mul_f2i(&a, &x, &y, &z);
}
else {
p = s2p(a.size + a.size);
i2f(&x, &a, p);
mul_f2i(&a, &x, &x, &z);
p = s2p(b.size + b.size);
i2f(&y, &b, p);
mul_f2i(&b, &y, &y, &z);
add_i(&a, &a, &b);
}
printf("F(%llu) = ", n);
print(&a);
printf("\r\n");
free_i(&a);
free_i(&b);
free_i(&c);
free_f(&x);
free_f(&y);
free_f(&z);
}
int main(){
f(1000000000);
return 0;
}
I2luY2x1ZGUgPHN0ZGludC5oPgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgPHN0ZGxpYi5oPgojaW5jbHVkZSA8bWF0aC5oPgoKY29uc3QgdWludDMyX3QgUkFESVggPSAxMDAwMDsKY29uc3QgZG91YmxlIHBpID0gMy4xNDE1OTI2NTM1ODk3OTMyMzg1OwoKZG91YmxlIGNvczE7CmRvdWJsZSBzaW4xOwoKdm9pZCBmcihkb3VibGUgKnMxLGRvdWJsZSAqczIsZG91YmxlICplbmQsc2l6ZV90IGFkZCxzaXplX3QgdDkwKXsKCWZvcig7czE8ZW5kO3MxKz1hZGQsczIrPWFkZCl7CgkJZG91YmxlIHIwLHIxLHIyLHIzLG0wLG0xOwoKCQlyMD1zMVswXTsKCQlyMT1zMlswXTsKCQlyMj1zMVt0OTBdOwoJCXIzPXMyW3Q5MF07CgoJCW0wPXIyKmNvczEtcjMqc2luMTsKCQltMT1yMipzaW4xK3IzKmNvczE7CgoJCXMxWzBdICAgPSByMCttMDsKCQlzMlswXSAgID0gcjAtbTA7CgkJczFbdDkwXSA9LXIxK20xOwoJCXMyW3Q5MF0gPSByMSttMTsKCX0KfQoKdm9pZCBmcmkoZG91YmxlICpzMSxkb3VibGUgKnMyLGRvdWJsZSAqZW5kLHNpemVfdCBhZGQsc2l6ZV90IHQ5MCl7Cglmb3IoO3MxPGVuZDtzMSs9YWRkLHMyKz1hZGQpewoJCWRvdWJsZSByMCxyMSxyMixyMyxtMCxtMSxtMixtMzsKCgkJcjA9czFbMF07CgkJcjE9czJbMF07CgkJcjI9czFbdDkwXTsKCQlyMz1zMlt0OTBdOwoKCQltMD0gcjArcjE7CgkJbTE9LXIyK3IzOwoJCW0yPSByMC1yMTsKCQltMz0gcjIrcjM7CgoJCXMxWzBdICAgPSBtMDsKCQlzMlswXSAgID0gbTE7CgkJczFbdDkwXSA9IG0yKmNvczErbTMqc2luMTsKCQlzMlt0OTBdID0tbTIqc2luMSttMypjb3MxOwoJfQp9Cgp2b2lkIGZyMChkb3VibGUgKnMxLGRvdWJsZSAqZW5kLHNpemVfdCBhZGQsc2l6ZV90IHQ5MCl7Cglmb3IoO3MxPGVuZDtzMSs9YWRkKXsKCQlkb3VibGUgcjAscjE7CgoJCXIwPXMxWzBdOwoJCXIxPXMxW3Q5MF07CgoJCXMxWzBdID1yMCtyMTsKCQlzMVt0OTBdID1yMC1yMTsKCX0KfQoKdm9pZCBzd2FwX2QoZG91YmxlICphLCBkb3VibGUgKmIpIHsKCWRvdWJsZSB0ID0gKmE7CgkqYSA9ICpiOwoJKmIgPSB0Owp9Cgp2b2lkIGJ4Y2hnKGRvdWJsZSAqcyxpbnQgcCl7CglzaXplX3QgdDQsIHQ1LCB0NjsKCXNpemVfdCB0MDQ1LCB0MDkwLCB0MTgwLCB0MjcwOwoKCXQwNDUgPSAoc2l6ZV90KTE8PHAtMzsKCXQwOTAgPSB0MDQ1ICsgdDA0NTsKCXQxODAgPSB0MDkwICsgdDA5MDsKCXQyNzAgPSB0MTgwICsgdDA5MDsKCgl0NCA9IHQwOTAgLSA0OwoJdDUgPSB0NDsKCWRvIHsKCQlzd2FwX2QoJnNbdDQrMV0sICZzW3QxODArdDVdKTsKCQlzd2FwX2QoJnNbdDQrMl0sICZzW3QwOTArdDVdKTsKCQlzd2FwX2QoJnNbdDQrM10sICZzW3QyNzArdDVdKTsKCQlzd2FwX2QoJnNbdDA5MCt0NCsxXSwgJnNbdDE4MCt0NSsyXSk7CgkJc3dhcF9kKCZzW3QwOTArdDQrM10sICZzW3QyNzArdDUrMl0pOwoJCXN3YXBfZCgmc1t0MTgwK3Q0KzNdLCAmc1t0MjcwK3Q1KzFdKTsKCgkJaWYodDQgPCB0NSl7CgkJCXN3YXBfZCgmc1t0NF0sICZzW3Q1XSk7CgkJCXN3YXBfZCgmc1t0MDkwK3Q0KzJdLCAmc1t0MDkwK3Q1KzJdKTsKCQkJc3dhcF9kKCZzW3QxODArdDQrMV0sICZzW3QxODArdDUrMV0pOwoJCQlzd2FwX2QoJnNbdDI3MCt0NCszXSwgJnNbdDI3MCt0NSszXSk7CgkJfQoJCWlmICh0NCA9PSAwKXsKCQkJYnJlYWs7CgkJfQoKCQl0NCAtPSA0OwoJCXQ2ID0gdDA0NTsKCQlmb3IoOzspewoJCQl0NSBePSB0NjsKCQkJaWYoKHQ1ICYgdDYpID09IDApewoJCQkJYnJlYWs7CgkJCX0KCQkJdDYgPj49IDE7CgkJfQoJfSB3aGlsZSAoMSk7Cn0KCnZvaWQgYml0ZXhjaGcoZG91YmxlICpzLGludCBwKXsKCWlmIChwIDw9IDEpewoJfQoJZWxzZSBpZiAocCA9PSAyKXsKCQlzd2FwX2QoJnNbMV0sJnNbMl0pOwoJfQoJZWxzZSBpZiAocCA9PSAzKXsKCQlzd2FwX2QoJnNbMV0sJnNbNF0pOwoJCXN3YXBfZCgmc1szXSwmc1s2XSk7Cgl9CgllbHNlIHsKCQlieGNoZyhzLHApOwoJfQp9Cgpkb3VibGUqIFNJTl9UQUJMRVs2NF0gPSB7MH07Cgpjb25zdCBkb3VibGUqIHNpbl90YWJsZShpbnQgcCl7CglpZiAocCA+PSAyICYmIFNJTl9UQUJMRVtwXSA9PSAwKXsKCQlzaXplX3QgdDA5MCA9IChzaXplX3QpMTw8cC0yOwoJCVNJTl9UQUJMRVtwXSA9IChkb3VibGUqKW1hbGxvYyh0MDkwKnNpemVvZihkb3VibGUpKTsKCQlkb3VibGUgayA9IDAuNSAqIHBpIC8gdDA5MDsKCQlmb3IgKGludCBpID0gMCA7IGkgPCB0MDkwIDsgaSsrKXsKCQkJU0lOX1RBQkxFW3BdW2ldID0gc2luKGsgKiBpKTsKCQl9Cgl9CglyZXR1cm4gU0lOX1RBQkxFW3BdOwp9Cgp2b2lkIGZvdXJpKGRvdWJsZSAqcywgaW50IHApewoJY29uc3QgZG91YmxlKiB0YWJsZSA9IHNpbl90YWJsZShwKTsKCgliaXRleGNoZyhzLHApOwoKCXNpemVfdCBxID0gKHNpemVfdCkxPDxwOwoKCWZvciAoaW50IGkgPSAxO2kgPD0gcDsgaSsrKXsKCQlzaXplX3QgcjM2MCA9IChzaXplX3QpMTw8aTsKCQlzaXplX3QgcjE4MCA9IHIzNjAgLyAyOwoJCXNpemVfdCByMDkwID0gcjE4MCAvIDI7CgkJc2l6ZV90IGsxID0gMDsKCQlzaXplX3QgazIgPSByMTgwIC0gMTsKCgkJZnIwKCZzWzBdLCAmc1txXSwgcjM2MCwgcjE4MCk7CgkJazEgKys7CgoJCXNpemVfdCB0MCA9IChzaXplX3QpMTw8cC1pOwoJCXNpemVfdCB0MSA9ICgoc2l6ZV90KTE8PHAtMikgLSB0MDsKCQlzaXplX3QgdDIgPSAoc2l6ZV90KTE8PHAtaTsKCQlmb3IgKDtrMSA8IHIwOTA7azEgKyssazIgLS0pewoJCQlzaW4xID0gdGFibGVbdDBdOwoJCQljb3MxID0gdGFibGVbdDFdOwoJCQlmcigmc1trMV0sICZzW2syXSwgJnNbcV0sIHIzNjAsIHIxODApOwoJCQl0MCArPSB0MjsKCQkJdDEgLT0gdDI7CgkJfQoJfQp9Cgp2b2lkIGZvdXJpaW52KGRvdWJsZSAqcywgaW50IHApewoJY29uc3QgZG91YmxlKiB0YWJsZSA9IHNpbl90YWJsZShwKTsKCglzaXplX3QgcSA9IChzaXplX3QpMTw8cDsKCglmb3IgKGludCBpID0gcDtpID49IDE7IGktLSl7CgkJc2l6ZV90IHIzNjAgPSAoc2l6ZV90KTE8PGk7CgkJc2l6ZV90IHIxODAgPSByMzYwIC8gMjsKCQlzaXplX3QgcjA5MCA9IHIxODAgLyAyOwoJCXNpemVfdCBrMSA9IDA7CgkJc2l6ZV90IGsyID0gcjE4MCAtIDE7CgoJCWZyMCgmc1swXSwgJnNbcV0sIHIzNjAsIHIxODApOwoJCWsxICsrOwoKCQlzaXplX3QgdDAgPSAoc2l6ZV90KTE8PHAtaTsKCQlzaXplX3QgdDEgPSAoKHNpemVfdCkxPDxwLTIpIC0gdDA7CgkJc2l6ZV90IHQyID0gKHNpemVfdCkxPDxwLWk7CgkJZm9yICg7azEgPCByMDkwO2sxICsrLGsyIC0tKXsKCQkJc2luMSA9IHRhYmxlW3QwXTsKCQkJY29zMSA9IHRhYmxlW3QxXTsKCQkJZnJpKCZzW2sxXSwgJnNbazJdLCAmc1txXSwgcjM2MCwgcjE4MCk7CgkJCXQwICs9IHQyOwoJCQl0MSAtPSB0MjsKCQl9Cgl9CgliaXRleGNoZyhzLHApOwp9CgppbnQgczJwKHVpbnQ2NF90IHMpIHsKCWludCBpOwoJZm9yIChpID0gMDsgaSA8IDY0OyBpKyspIHsKCQlpZiAoKHNpemVfdCkxIDw8IGkgPj0gcykgewoJCQlicmVhazsKCQl9Cgl9CglyZXR1cm4gaTsKfQoKdHlwZWRlZiBzdHJ1Y3QgSV8gewoJdWludDE2X3QgKmRhdGE7CglzaXplX3QgY2FwYWNpdHk7CglzaXplX3Qgc2l6ZTsKfSBJOwoKdHlwZWRlZiBzdHJ1Y3QgRl8gewoJZG91YmxlICpkYXRhOwoJc2l6ZV90IGNhcGFjaXR5OwoJaW50IHA7Cn0gRjsKCnZvaWQgYWxsb2NfaShJICphLCBzaXplX3QgY2FwKXsKCWEtPmRhdGEgPSAodWludDE2X3QqKW1hbGxvYyhjYXAgKiBzaXplb2YodWludDE2X3QpKTsKCWEtPmNhcGFjaXR5ID0gY2FwOwp9Cgp2b2lkIGZyZWVfaShJICphKSB7CglmcmVlKGEtPmRhdGEpOwp9Cgp2b2lkIGFsbG9jX2YoRiAqYSwgaW50IHApIHsKCXNpemVfdCBjYXAgPSAoc2l6ZV90KTEgPDwgcDsKCWEtPmRhdGEgPSAoZG91YmxlKiltYWxsb2MoY2FwICogc2l6ZW9mKGRvdWJsZSkpOwoJYS0+Y2FwYWNpdHkgPSBjYXA7Cn0KCnZvaWQgZnJlZV9mKEYgKmEpewoJZnJlZShhLT5kYXRhKTsKfQoKdm9pZCBzd2FwX2koSSAqYSwgSSAqYikgewoJSSB0ID0gKmE7CgkqYSA9ICpiOwoJKmIgPSB0Owp9Cgp2b2lkIGkyZihGICphLCBjb25zdCBJICpiLCBpbnQgcCl7CglzaXplX3QgaTsKCXNpemVfdCB0MzYwID0gKHNpemVfdCkxIDw8IHA7CgoJYS0+cCA9IHA7CgoJaW50IGNhcnJ5ID0gMDsKCWZvciAoaSA9IDA7IGkgPCBiLT5zaXplIC0xOyBpKyspewoJCWludCB0ID0gYi0+ZGF0YVtpXSArIGNhcnJ5OwoJCWlmICh0IDwgKGludClSQURJWC8yKXsKCQkJYS0+ZGF0YVtpXSA9IHQ7CgkJCWNhcnJ5ID0gMDsKCQl9CgkJZWxzZSB7CgkJCWEtPmRhdGFbaV0gPSAoaW50KXQgLSAoaW50KVJBRElYOwoJCQljYXJyeSA9IDE7CgkJfQoJfQoJYS0+ZGF0YVtpKytdID0gYi0+ZGF0YVtpXSArIGNhcnJ5OwoJZm9yICg7IGkgPCB0MzYwOyBpKyspIHsKCQlhLT5kYXRhW2ldID0gMC47Cgl9Cglmb3VyaShhLT5kYXRhLCBwKTsKfQoKdm9pZCBtdWxfZjJpKEkgKmEsIGNvbnN0IEYgKmIsIGNvbnN0IEYgKmMsIEYgKmQpewoJaW50IHAgPSBiLT5wOwoJc2l6ZV90IHQxODAgPSAoc2l6ZV90KTEgPDwgcC0xOwoJc2l6ZV90IHQzNjAgPSB0MTgwICsgdDE4MDsKCXNpemVfdCBpOwoJaW50NjRfdCBjYXJyeTsKCXNpemVfdCB0OwoJc2l6ZV90IHM7CgoJZC0+ZGF0YVswXSA9IGItPmRhdGFbMF0gKiBjLT5kYXRhWzBdICogLjU7CglkLT5kYXRhW3QxODBdID0gYi0+ZGF0YVt0MTgwXSAqIGMtPmRhdGFbdDE4MF0gKiAuNTsKCXsKCQlzaXplX3QgazEgPSAxOwoJCXNpemVfdCBrMiA9ICgoc2l6ZV90KTE8PHApLTE7CgkJc2l6ZV90IGVuZCA9IHQxODA7CgkJZm9yICg7IGsxIDwgZW5kIDsgazErKyxrMi0tKXsKCQkJZG91YmxlIHJlID0gYi0+ZGF0YVtrMV0gKiBjLT5kYXRhW2sxXSAtIGItPmRhdGFbazJdICogYy0+ZGF0YVtrMl07CgkJCWRvdWJsZSBpbSA9IGItPmRhdGFbazFdICogYy0+ZGF0YVtrMl0gKyBiLT5kYXRhW2syXSAqIGMtPmRhdGFbazFdOwoJCQlkLT5kYXRhW2sxXSA9IHJlOwoJCQlkLT5kYXRhW2syXSA9IGltOwoJCX0KCX0KCglmb3VyaWludihkLT5kYXRhLCBwKTsKCglzID0gYS0+Y2FwYWNpdHkgPCB0MzYwID8gYS0+Y2FwYWNpdHkgOiB0MzYwOwoKCWNhcnJ5ID0gMDsKCXQgPSAxOwoJZG91YmxlIGsgPSBsZGV4cCgxLiwgLXArMSk7Cglmb3IgKGkgPSAwIDsgaSA8IHMgOyBpKyspewoJCWludDY0X3QgZSA9IChpbnQ2NF90KWZsb29yKGQtPmRhdGFbaV0gKiBrICsgLjUpICsgY2Fycnk7CgkJaW50MTZfdCBmOwoJCWNhcnJ5ID0gZSAvIFJBRElYOwoJCWYgPSAoaW50MTZfdCkoZSAtIGNhcnJ5ICogUkFESVgpOwoJCWlmIChmIDwgMCl7CgkJCWYgKz0gUkFESVg7CgkJCWNhcnJ5IC0tOwoJCX0KCQlhLT5kYXRhW2ldID0gZjsKCQlpZiAoZiAhPSAwKSB7CgkJCXQgPSBpICsgMTsKCQl9Cgl9CglhLT5zaXplID0gdDsKfQoKdm9pZCBhZGRfaShJICphLCBjb25zdCBJICpiLCBjb25zdCBJICpjKSB7Cgl1aW50MTZfdCBjYXJyeSA9IDA7CglzaXplX3QgaTsKCWlmIChiLT5zaXplID4gYy0+c2l6ZSl7CgkJY29uc3QgSSAqdCA9IGI7CgkJYiA9IGM7CgkJYyA9IHQ7Cgl9CgoJZm9yIChpID0gMDsgaSA8IGItPnNpemU7IGkrKykgewoJCXVpbnQxNl90IGQgPSBiLT5kYXRhW2ldICsgYy0+ZGF0YVtpXSArIGNhcnJ5OwoJCWNhcnJ5ID0gMDsKCQlpZiAoZCA+PSBSQURJWCl7CgkJCWQgLT0gUkFESVg7CgkJCWNhcnJ5ICsrOwoJCX0KCQlhLT5kYXRhW2ldID0gZDsKCX0KCWZvciAoOyBpIDwgYy0+c2l6ZTsgaSsrKSB7CgkJdWludDE2X3QgZCA9IGMtPmRhdGFbaV0gKyBjYXJyeTsKCQljYXJyeSA9IDA7CgkJaWYgKGQgPj0gUkFESVgpewoJCQlkIC09IFJBRElYOwoJCQljYXJyeSArKzsKCQl9CgkJYS0+ZGF0YVtpXSA9IGQ7Cgl9CglhLT5zaXplID0gYy0+c2l6ZTsKCWlmIChjYXJyeSAhPSAwKXsKCQlhLT5kYXRhW2EtPnNpemUrK10gPSBjYXJyeTsKCX0KfQoKdm9pZCBwcmludChjb25zdCBJICphKXsKCXNpemVfdCBzID0gYS0+c2l6ZTsKCXByaW50ZigiJXUiLCBhLT5kYXRhWy0tc10pOwoJd2hpbGUgKHMgIT0gMCkgewoJCXByaW50ZigiJTA0dSIsIGEtPmRhdGFbLS1zXSk7Cgl9Cn0KCnZvaWQgZih1aW50NjRfdCBuKXsKCUkgYSwgYiwgYzsKCUYgeCwgeSwgejsKCWludCBpLCBwOwoKCXsKCQlzaXplX3QgY2FwID0gKHNpemVfdClmbG9vcigobG9nKHNxcnQoMS4yNSkgKyAuNSkqbiAtIDAuNSpsb2coNS4pKSAqICgxLiAvIGxvZygoZG91YmxlKVJBRElYKSkgKyAyLjAwMSk7CgkJaWYgKGNhcCA8PSAyKSB7CgkJCWNhcCA9IDI7CgkJfQoJCXAgPSBzMnAoY2FwKTsKCQlhbGxvY19pKCZhLCBjYXApOwoJCWFsbG9jX2koJmIsIGNhcCk7CgkJYWxsb2NfaSgmYywgY2FwKTsKCQlhbGxvY19mKCZ4LCBwKTsKCQlhbGxvY19mKCZ5LCBwKTsKCQlhbGxvY19mKCZ6LCBwKTsKCQlhLmRhdGFbMF0gPSAxOwoJCWEuc2l6ZSA9IDE7CgkJYi5kYXRhWzBdID0gMDsKCQliLnNpemUgPSAxOwoJfQoKCWZvciAoaSA9IDYzOyBpID4gMDsgaS0tKSB7CgkJcCA9IHMycChiLnNpemUgKyBiLnNpemUpOwoJCWkyZigmeCwgJmEsIHApOwoJCWkyZigmeSwgJmIsIHApOwoJCW11bF9mMmkoJmMsICZ5LCAmeSwgJnopOwoJCW11bF9mMmkoJmEsICZ4LCAmeCwgJnopOwoJCWFkZF9pKCZhLCAmYSwgJmMpOwoJCW11bF9mMmkoJmIsICZ4LCAmeSwgJnopOwoJCWFkZF9pKCZiLCAmYiwgJmIpOwoJCWFkZF9pKCZiLCAmYiwgJmMpOwoJCWlmIChuKzEgJiAoc2l6ZV90KTEgPDwgaSkgewoJCQlhZGRfaSgmYSwgJmEsICZiKTsKCQkJc3dhcF9pKCZhLCAmYik7CgkJfQoJfQoJaWYgKG4rMSAmIDEpIHsKCQlhZGRfaSgmYSwgJmEsICZhKTsKCQlhZGRfaSgmYSwgJmEsICZiKTsKCQlwID0gczJwKGEuc2l6ZSArIGIuc2l6ZSk7CgkJaTJmKCZ4LCAmYSwgcCk7CgkJaTJmKCZ5LCAmYiwgcCk7CgkJbXVsX2YyaSgmYSwgJngsICZ5LCAmeik7Cgl9CgllbHNlIHsKCQlwID0gczJwKGEuc2l6ZSArIGEuc2l6ZSk7CgkJaTJmKCZ4LCAmYSwgcCk7CgkJbXVsX2YyaSgmYSwgJngsICZ4LCAmeik7CgkJcCA9IHMycChiLnNpemUgKyBiLnNpemUpOwoJCWkyZigmeSwgJmIsIHApOwoJCW11bF9mMmkoJmIsICZ5LCAmeSwgJnopOwoJCWFkZF9pKCZhLCAmYSwgJmIpOwoJfQoKCXByaW50ZigiRiglbGx1KSA9ICIsIG4pOwoJcHJpbnQoJmEpOwoJcHJpbnRmKCJcclxuIik7CgoJZnJlZV9pKCZhKTsKCWZyZWVfaSgmYik7CglmcmVlX2koJmMpOwoJZnJlZV9mKCZ4KTsKCWZyZWVfZigmeSk7CglmcmVlX2YoJnopOwp9CgppbnQgbWFpbigpewoJZigxMDAwMDAwMDAwKTsKCXJldHVybiAwOwp9Cg==