Cod sursa(job #2007268)

Utilizator Coroian_DavidCoroian David Coroian_David Data 2 august 2017 13:25:30
Problema Fractal Scor 90
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.92 kb
#include <cstdio>

#include <map>

#include <cassert>

using namespace std;

FILE *f, *g;

typedef long long lint;

map <pair<pair<pair<pair<lint , lint >, lint >, lint >, lint >, lint >rez;

lint k, x, y;

void readFile()
{
    f = fopen("fractal.in", "r");

    fscanf(f, "%lld%lld%lld", &k, &y, &x);

    fclose(f);
}

lint rezz;

lint getZona(lint x1, lint y1, lint p2)
{
    if(x1 > p2 && y1 > p2)
        return 3;

    if(x1 > p2 && y1 <= p2)
        return 2;

    if(x1 <= p2 && y1 > p2)
        return 4;

    return 1;
}

const lint l[] = {0, 0, 1, 1, 0};
const lint c[] = {0, 0, 0, 1, 1};

void to1(lint &l, lint &c, lint p2)
{
    lint aux = c;
    c = p2 - l + 1;
    l = aux;
}

void to4(lint &l, lint &c, lint p2)
{
    lint aux = c;
    c = l;
    l = p2 - aux + 1;
}

lint drum(lint k, lint x1, lint y1, lint x2, lint y2);

lint drumuri(lint k, lint x1, lint y1, lint x2, lint y2, lint p2, lint z1, lint z2)
{
   // printf("DRUMURI K=%d c1: %d %d c2: %d %d z: %d %d\n", k, x1, y1, x2, y2, z1, z2);

    if(z1 == 2 && z2 == 3)
    {
        lint midx1 = p2 + 1;
        lint midy1 = p2;

        lint midx2 = p2 + 1;
        lint midy2 = p2 + 1;

        return rez[{{{{k, x1}, y1}, x2}, y2}] = 1 + drum(k - 1, x1 - p2, y1, midx1 - p2, midy1) + drum(k - 1, x2 - p2, y2 - p2, midx2 - p2, midy2 - p2);
    }

    if(z1 == 1 && z2 == 2)
    {
        lint midx1 = p2;
        lint midy1 = 1;

        lint midx2 = p2 + 1;
        lint midy2 = 1;

        to1(midx1, midy1, p2);
        to1(x1, y1, p2);

        return rez[{{{{k, x1}, y1}, x2}, y2}] = 1 + drum(k - 1, x1, y1, midx1, midy1) + drum(k - 1, x2 - p2, y2, midx2 - p2, midy2);
    }

    if(z1 == 3 && z2 == 4)
    {
        lint midx1 = p2 + 1;
        lint midy1 = p2 * 2;

        lint midx2 = p2;
        lint midy2 = p2 * 2;///<< 1

        to4(midx2, midy2, p2 * 2);
        to4(x2, y2, p2 * 2);

        return rez[{{{{k, x1}, y1}, x2}, y2}] = 1 + drum(k - 1, x1 - p2, y1 - p2, midx1 - p2, midy1 - p2) + drum(k - 1, x2, y2 /*- p2*/, midx2, midy2 /*- p2*/);
    }

    if(z1 == 1 && z2 == 4)
    {
        lint midx1 = p2 + 1;
        lint midy1 = 1;

        lint midx2 = p2 + 1;
        lint midy2 = p2 + 1;

        return rez[{{{{k, x1}, y1}, x2}, y2}] = drumuri(k, x1, y1, midx1, midy1, p2, 1,2) + drumuri(k, midx1, midy1, midx2, midy2, p2, 2, 3) + drumuri(k, midx2, midy2, x2, y2, p2, 3, 4);
    }

    if(z1 == 2 && z2 == 4)
    {
        lint midx2 = p2 + 1;
        lint midy2 = p2 + 1;

        return rez[{{{{k, x1}, y1}, x2}, y2}] = drumuri(k, x1, y1, midx2, midy2, p2, 2, 3) + drumuri(k, midx2, midy2, x2, y2, p2, 3, 4);
    }

    if(z1 == 1 && z2 == 3)
    {
        lint midx1 = p2 + 1;
        lint midy1 = 1;

        return rez[{{{{k, x1}, y1}, x2}, y2}] = drumuri(k, x1, y1, midx1, midy1, p2, 1,2) + drumuri(k, midx1, midy1, x2, y2, p2, 2, 3);
    }

    return 0;
}

void schimba(lint &a, lint &b)
{
    lint aux = a;
    a = b;
    b = aux;
}

lint drum(lint k, lint x1, lint y1, lint x2, lint y2)
{
   // printf("K=%d c1: %d %d c2: %d %d\n", k, x1, y1, x2, y2);

    assert(x1 > 0 && y1 > 0 && x2 > 0 && y2 > 0);

    lint pp = (1 << k)+1;

    assert(x1 < pp && y1 < pp && x2 < pp && y2 < pp);

    if(x1 == x2 && y1 == y2)
        return 0;

    if(k == 1)
    {
        if(x1 == 1 && x2 == 1)
            return 3;

        if(x1 == 2 && x2 == 2)
            return 1;

        if(y1 == y2)
            return 1;

        return 2;
    }

    if(rez[{{{{k, x1}, y1}, x2}, y2}] != 0)
        return rez[{{{{k, x1}, y1}, x2}, y2}];

    lint p2 = (1 << (k - 1));

    lint z1 = getZona(x1, y1, p2);
    lint z2 = getZona(x2, y2, p2);


  //  printf("+++++++++K=%d c1: %d %d c2: %d %d z: %d %d\n", k, x1, y1, x2, y2, z1, z2);

    if(z1 > z2)
    {
        schimba(x1, x2);
        schimba(y1, y2);
        schimba(z1, z2);
    }



    //printf("+++++++++K=%d c1: %d %d c2: %d %d z: %d %d\n", k, x1, y1, x2, y2, z1, z2);

    if(z1 == z2)
    {
        if(z1 == 2 || z1 == 3)
            return rez[{{{{k, x1}, y1}, x2}, y2}] = drum(k - 1, x1 - p2 * l[z1], y1 - p2 * c[z1], x2 - p2 * l[z1], y2 - p2 * c[z1]);

        else
        {
            if(z1 == 1)
            {
                to1(x1, y1, p2);
                to1(x2, y2, p2);
            }

            if(z1 == 4)
            {
                to4(x1, y1, p2 * 2);
                to4(x2, y2, p2 * 2);
            }

            return rez[{{{{k, x1}, y1}, x2}, y2}] = drum(k - 1, x1, y1, x2, y2);
        }
    }

    return rez[{{{{k, x1}, y1}, x2}, y2}] = drumuri(k, x1, y1, x2, y2, p2, z1, z2);
}

void solve()
{
    rezz = drum(k, 1, 1, x, y);
}

void printFile()
{
    g = fopen("fractal.out", "w");

    fprintf(g, "%lld\n", rezz);

    fclose(g);
}

int main()
{
    readFile();

    solve();

    printFile();

    return 0;
}