Cod sursa(job #18684)

Utilizator victorsbVictor Rusu victorsb Data 18 februarie 2007 12:58:23
Problema Ghiozdan Scor 0
Compilator cpp Status done
Runda preONI 2007, Runda 2, Clasele 11-12 Marime 2.4 kb
#include <cstdio>
#include <deque>

using namespace std;

#define inf 1000000000
#define Nmax 20001
#define Gmax 75005
#define Vmax 201
#define x first
#define pos second
#define mp make_pair
#define sz size()

int n, g, a, smax, s, maxv, size;
int ct[Vmax], sol[Vmax][Gmax];
char nr[Vmax][Gmax];
deque<int> Q;

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;
    memset(sol, 0x3f, sizeof(sol));
    sol[0][0] = 0;
    for (i = 1; i <= maxv; ++i)
    {
    if (ct[i])
    {
        for (j = 0; j < i; ++j)
        {
            Q.clear();
            size = 0;
            for (k = j; k <= g; k += i)
            {
                while (k - Q[0] > ct[i] * i)
                {
                    Q.pop_front();
                    --size;
                }
                
                sol[i][k] = sol[i-1][k];
                nr[i][k] = 0;
                
                if (size > 0)
                    if (sol[i-1][Q[0]] + ((k - Q[0]) / i) < sol[i][k])
                    {
                        sol[i][k] = sol[i-1][Q[0]] + ((k - Q[0]) / i);
                        nr[i][k] = (k - Q[0]) / i;
                    }
                
                while (size > 0 && sol[i - 1][Q[size - 1]] > sol[i - 1][k])
                {
                    Q.pop_back();
                    --size;
                }                
                Q.push_back(k);
                ++size;
            }
        }
    }
    
    for (j = 0; j <= g; ++j)
        sol[i][j] = min(sol[i][j], sol[i-1][j]);
    }
    
    for (smax = g; smax >= 0; --smax)
        if (sol[maxv][smax] < inf)
            break;

    memset(ct, 0, sizeof(ct));
    scrie(maxv, smax);

    for (i = 1; i <= Vmax; ++i)
        s += ct[i];
    printf("%d %d\n", smax, s);
    for (i = 1; i <= Vmax; ++i)
        if (ct[i])
            for (j = 1; j <= ct[i]; ++j)
                printf("%d\n", i);
}


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