Cod sursa(job #626663)

Utilizator Bit_MasterAlexandru-Iancu Caragicu Bit_Master Data 27 octombrie 2011 21:12:07
Problema Ghiozdan Scor 30
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.33 kb
/*
    d[i][j] -> nr min de obiecte pt a obtine greutatea j
            folosind obiectele de la 1 la i
    d[i][j] = min(d[i-1][j],d[i-1][j-g[i]] + 1)
        unde g[i] este greutatea obiectului nr i

    dinamica pe 2 linii
    pt reconstituirea drumului folosesc ca la sol in O(N)
    de la cmlsc din arhiva educationala (cel mai lung subsir
    comun) vectorul cu pozitie de sosire pe linia n/2.
    initializarile pt fiecare apel recursiv sunt cele
    obisnuite (consider ce obiecte as lua din intervalul x1...x2)

    solutie O(N) (merge si O(N*sqrt(N)), calculez dinamica retinand
    liniile din sqrt(N) in sqrt(N) si recalculez dinamica pt bucati de sqrt(N) linii dinamica
    pt a reconstitui drumul)
*/



#include <cstdio>

const int INF = 2000000000;

const int G = 75005;
const int N = 20005;

int d[2][G];
int g[N]; int n; int g_max;
int v[G],v_pred[G];/* sosirea liniei curente pe linia n/2
                    (in cazul nostru cel mai din dreapta
                      pct, la alte dinamici primul pct de
                      sosire a drumului in sens invers pe
                      linia (x1+x2)/2) */

inline int min(int a, int b)
{
    return (a<b)?a:b;
}

void citire()
{
    scanf("%d%d",&n,&g_max);
    for (int i = 1; i <= n; ++i)
        scanf("%d",&g[i]);
}

void dinamica(int x1, int y1, int x2, int y2)
{
    //cazul banal
    if (x1 == x2)//greut maxima ce se obtine luand un obiect
    {
        if (1 == n)//nu s-a apucat afisarea primelor 2 valori cerute
        {
            if (g[x1] <= y2-y1)     //inainte y2-y1+1
                printf("%d %d\n",g[x1],1);
            else
                printf("%d %d\n",0,0);
        }
        if (g[x1] <= y2-y1)
            printf("%d\n",g[x1]);
        return;
    }
    //initializare
    d[(x1-1)%2][y1-1] = 0;
    for (int j = y1; j <= y2; ++j)
        d[(x1-1)%2][j] = INF;     //0%2

    //calculare
    for (int i = x1; i <= x2; ++i)
    {
        d[i%2][y1-1] = 0;//init
        for (int j = y1; j <= y2; ++j)     //% nu merge pt numere negative (decat %2)
        {
            if (j - g[i] < y1-1)
                d[i%2][j] = d[(i-1)%2][j];
            else
                d[i%2][j] = min( d[(i-1)%2][j] , d[(i-1)%2][j-g[i]]+1 );
            if (i == (x1+x2)/2)
                v[j] = j;
            if (i > (x1+x2)/2)
            {
                if (j - g[i] < y1 - 1)
                    v[j] = v_pred[j];
                else
                    if (d[(i-1)%2][j] < d[(i-1)%2][j-g[i]]+1)
                        v[j] = v_pred[j];
                    else
                        v[j] = v_pred[j-g[i]];
            }
        }
        if (i >= (x1+x2)/2)
            for (int j = y1; j <= y2; ++j)
                v_pred[j] = v[j];
    }

    //calculare greutate maxima posibila
    int j_umplere;
    for (int j = y2; y1 <= j; --j)
        if (d[x2%2][j] != INF)
        {
            j_umplere = j;
            break;
        }
    if (x1 == 1 && y1 == 1 && x2 == n && y2 == g_max)
        printf("%d %d\n",j_umplere,d[x2%2][j_umplere]);

    int aux = v[j_umplere];
    dinamica(x1,y1,(x1+x2)/2,aux);
    dinamica((x1+x2)/2+1,aux,x2,y2);
}

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