Cod sursa(job #19180)

Utilizator victorsbVictor Rusu victorsb Data 18 februarie 2007 20:50:19
Problema Ghiozdan Scor 84
Compilator cpp Status done
Runda Arhiva de probleme Marime 5.12 kb
#include <cstdio>
#include <deque>

using namespace std;

#define inf 1000000000
#define rad 14
#define Nmax 20001
#define Gmax 75001
#define Vmax 205
#define x first
#define pos second
#define mp make_pair
#define sz size()

int n, g, a, smax, s, maxv, size;
int ct[Vmax];
int sol[20][Gmax];
int sol2[20][Gmax];
char nr[20][Gmax];
int Q[Gmax];

void citire()
{
    int i;
    scanf("%d %d\n", &n, &g);
    for (i = 1; i <= n; ++i)
    {
        scanf("%d\n", &a);
        ++ct[a];
        if (a > maxv)
            maxv = a;
    }
}

void scrie(int num, int suma)
{
    if (num == 0)
        return;
    ct[num] = nr[num][suma];
    suma -= num * ct[num];
    scrie(num - 1, suma);
}

void solve()
{
    int i, j, k, l, st, dr, pas, gr = 0;
    memset(sol, 0x3f, sizeof(sol));
    memset(sol2, 0x3f, sizeof(sol2));
    sol[0][0] = 0;
    sol2[0][0] = 0;
    for (pas = 1; pas <= maxv; ++pas)
    {
        i = pas % rad ? pas % rad : rad;
        
        if (ct[pas])
        {
            for (j = 0; j < pas; ++j)
            {
                st = 1;
                dr = 0;
                if (j == 0)
                    Q[++dr] = 0;
                    
                for (k = j; k <= g; k += pas)
                {
                    if (st <= dr)
                    while (k - Q[st] > ct[pas] * pas)
                        ++st;
                    sol[i][k] = sol[i-1][k];
                    nr[i][k] = 0;
                    
                    if (st <= dr)
                        if (sol[i-1][Q[st]] + ((k - Q[st]) / pas) < sol[i][k])
                        {
                            sol[i][k] = sol[i-1][Q[st]] + ((k - Q[st]) / pas);
                            nr[i][k] = (k - Q[st]) / pas;
                        }
                    
                    while (st <= dr && sol[i - 1][Q[dr]] > sol[i - 1][k])
                        --dr;
                    Q[++dr] = k;
                }
            }
        }
        for (j = 0; j <= g; ++j)
            sol[i][j] = min(sol[i][j], sol[i-1][j]);
        /*
        for (j = 0; j <= g; ++j)
            printf("%d ", sol[i][j]);
        printf("\n");
        */
        if (pas % rad == 0)
        {
            //printf("\n");
            if (pas != maxv)
                ++gr;
            for (j = 0; j <= g; ++j)
                sol2[pas / rad][j] = sol[rad][j];
            memset(sol, 0x3f, sizeof(sol));
            for (j = 0; j <= g; ++j)
                sol[0][j] = sol2[pas / rad][j];
        }
    }
    --pas;


    for (smax = g; smax >= 0; --smax)
        if (sol[pas % rad ? pas % rad : rad][smax] < inf)
            break;
    printf("%d %d\n", smax, sol[pas % rad ? pas % rad : rad][smax]);
    
    //printf("%d\n", gr);
    for (; gr >= 0; --gr)
    {
        memset(sol, 0x3f, sizeof(sol));
        memset(nr, 0, sizeof(nr));
        for (j = 0; j <= g; ++j)
            sol[0][j] = sol2[gr][j];
        /*
        for (pas = 0; pas <= rad; ++pas)
        {
            for (j = 0; j <= g; ++j)
                printf("%d ", sol[pas][j]);
            printf("\n");
        }
        printf("\n");*/
        
        //printf("%d %d\n", gr, smax);
        
        
        for (i = 1; i <= rad && rad * gr + i <= maxv; ++i)
        {
            pas = rad * gr + i;
            
            if (ct[pas])
            {
                for (j = 0; j < pas; ++j)
                {
                    st = 1;
                    dr = 0;
                    if (j == 0)
                        Q[++dr] = 0;
                        
                    for (k = j; k <= g; k += pas)
                    {
                        if (st <= dr)
                        while (k - Q[st] > ct[pas] * pas)
                            ++st;
                        sol[i][k] = sol[i-1][k];
                        nr[i][k] = 0;
                        
                        if (st <= dr)
                            if (sol[i-1][Q[st]] + ((k - Q[st]) / pas) < sol[i][k])
                            {
                                sol[i][k] = sol[i-1][Q[st]] + ((k - Q[st]) / pas);
                                nr[i][k] = (k - Q[st]) / pas;
                            }
                        
                        while (st <= dr && sol[i - 1][Q[dr]] > sol[i - 1][k])
                            --dr;
                        Q[++dr] = k;
                    }
                }
            }
            
            for (j = 0; j <= g; ++j)
                sol[i][j] = min(sol[i][j], sol[i-1][j]);
            /*
            for (j = 0; j <= g; ++j)
                printf("%d ", sol[i][j]);
            printf("\n");
            */
        }
        for (--i; i > 0; --i)
            if (nr[i][smax])
            {
                for (j = 1; j <= nr[i][smax]; ++j)
                    printf("%d\n", i + gr * rad);
                smax -= (i + gr * rad) * nr[i][smax];
            }
    }
    
}


int main()
{
    freopen("ghiozdan.in", "r", stdin);
    freopen("ghiozdan.out", "w", stdout);
    citire();
    solve();
    return 0;
}