Cod sursa(job #22583)

Utilizator filipbFilip Cristian Buruiana filipb Data 26 februarie 2007 20:36:03
Problema Ghiozdan Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.75 kb
#include <stdio.h>
#include <algorithm>
#define maxim(a, b) ((a > b) ? a : b)
#define minim(a, b) ((a < b) ? a : b)
#define INF 900000000
#define GMax 75005
#define x first
#define y second

using namespace std;

int N, G, c[201], max_g, sol[201], bst;

int S[2][GMax], mij[2][GMax], uz[GMax];
pair<int, int> q[GMax];

void PD(int side, int st, int dr, int G)
{
    int i, j, p, crt = 0, prev, first, last, lev;

    for (j = 1; j <= G; j++)
        S[!(st & 1)][j] = INF; 
    S[!(st & 1)][0] = 0; 
    
    for (i = st; i <= dr; i++)
    {        
        crt = (i & 1); prev = !crt;

        for (j = 0; j < i; j++)
        {
            q[first=last=0].x = 0, q[0].y = S[prev][j] + G;
            S[crt][j] = S[prev][j];
                        
            for (p = j+i, lev = 1; p <= G; p += i, lev++)
            {                        
                while (q[first].x < lev - c[i] && first <= last) first++;
                while (q[last].y > S[prev][p]+G-lev && last >= first) last--;                
                q[++last].x = lev, q[last].y = S[prev][p] + G - lev;

                S[crt][p] = q[first].y - G + lev;
                if (S[crt][p] > INF - G) S[crt][p] = INF;
            }

        }

    }

    for (i = 1; i <= G; i++)
        mij[side][i] = S[crt][i];
        
}

void rec(int st, int dr, int G)
// cu obiecte cu valoare intre st si dr sa obtin greutatea <= G
{
    int i, m, H, F1 = 0, max;

    if (st == dr)
    {
        sol[st] = minim(c[st], G / st);   
        return ;
    }

    m = (st + dr) / 2;

    PD(0, st, m, G);
    PD(1, m+1, dr, G);
    
    for (i = 1; i <= G; i++)
        if (mij[1][i] == INF) uz[i] = uz[i-1];
        else uz[i] = i;
        
    for (H = 0, max = -INF; H <= G; H++)
        if (mij[0][H] < INF && mij[1][uz[G-H]] < INF && H + uz[G-H] > max)
           max = H + uz[G-H], F1 = H;
        else if (mij[0][H] < INF && mij[1][uz[G-H]] < INF && 
                 H + uz[G-H] == max &&
                 mij[0][H] + mij[1][uz[G-H]] < mij[0][F1] + mij[1][max-F1])
           max = H + uz[G-H], F1 = H;
    
    if (st == 1 && dr == max_g)
       bst = max;
       
    rec(st, m, F1);
    rec(m+1, dr, max-F1);    
}

int main(void)
{
    int i, j, x;
    
    freopen("ghiozdan.in", "r", stdin);
    freopen("ghiozdan.out", "w", stdout);

    
    scanf("%d %d", &N, &G);
    for (i = 1; i <= N; i++)
    {
        scanf("%d", &x);
        c[x]++;
        max_g = maxim(max_g, x);
    }

    rec(1, max_g, G);
    
    for (x = 0, i = 1; i <= max_g; i++)
        x += sol[i];
    printf("%d %d\n", bst, x);
    
    for (i = 1; i <= max_g; i++)
        for (j = 1; j <= sol[i]; j++)
            printf("%d\n", i);
    
    return 0;
}