Cod sursa(job #2750980)

Utilizator NeacsuMihaiNeacsu Mihai NeacsuMihai Data 13 mai 2021 19:45:01
Problema Lapte Scor 0
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.48 kb
#include <iostream>
#include <fstream>
#include <cstring>

#define NMAX 100
#define LMAX 100
#define TIMPMINIM 1
#define TIMPMAXIM 100

using namespace std;

ifstream fin ("lapte.in");
ofstream fout ("lapte.out");

int N, L;
int v[NMAX + 1][LMAX / TIMPMINIM * NMAX + 1];
int RASPUNS;

struct persoana{
    int A, B;
}timp[NMAX + 1];

struct repartizare{
    int A, B;
}cantitate[NMAX + 1][2 * LMAX - 2 + 1];


int valid(int TIMP){
    //verific daca in acest timp, utilizand tactica optima, se pot bea L litri din fiecare lapte
    memset(v, 0, sizeof(v));
    int CAMAX = 2 * L - 2;

    //initializez
    for(int Ca = 0; Ca <= CAMAX; Ca++){
        v[1][Ca] = max(0, TIMP - Ca * timp[1].A / timp[1].B) ;

        if(v[1][Ca] != 0){
            cantitate[1][Ca].A = Ca;
            cantitate[1][Ca].B = TIMP - Ca * timp[1].A / timp[1].B;
        }
    }

    for(int i = 2; i <= N; i++){
        for(int Ca = 0; Ca <= CAMAX; Ca++){

            for(int Z = 0; Z <= Ca && TIMP - Z * timp[i].A >= 0; Z++){ //Z = cantitatea pe care omul i o bea din laptele A
                //v[i][Ca] = max(v[i][Ca], v[i - 1][Ca - Z] + (TIMP - Z * timp[i].A) / timp[i].B );
                if(v[i - 1][Ca - Z] != 0){

                    int candidat = v[i - 1][Ca - Z] + (TIMP - Z * timp[i].A) / timp[i].B;
                    if(i >= 1){
                        //cout << "Ca = " << Ca << "\ni = " << i << "\nZ = " << Z << "\ncandidat = v[ " << i - 1 << " ][ " << Ca - Z << " ]("<<v[i - 1][Ca - Z]<<") + ( " << TIMP << " - " << Z * timp[i].A << " ) / " << timp[i].B << " = " << candidat << "\nv[ " << i << " ][ " << Ca << " ] = " << v[i][Ca] << "\n\n";
                    }

                    if( candidat > v[i][Ca] ){
                        v[i][Ca] = candidat;
                        cantitate[i][Ca].A = Z;
                        cantitate[i][Ca].B = (TIMP - Z * timp[i].A) / timp[i].B;

                        for(int j = 1; j <= i - 1; j++){
                            cantitate[j][Ca].A = cantitate[j][Ca - Z].A;
                            cantitate[j][Ca].B = cantitate[j][Ca - Z].B;
                        }
                     }
                }
            }
        }

    }

    /*
    for(int i = 1; i <= N; i++){
        for(int j = 0; j <= CAMAX; j++){
            cout << "v[ " << i << " ][ " << j << " ] = " << v[i][j] << "\n";
        }
        cout << "\n";
    }
    cout << "\n";
    */


    int cntA = L;
    while(cntA <= CAMAX && v[N][cntA] == 0){
        cntA++;
    }

    if(cntA <= CAMAX){
        if(v[N][cntA] >= L){
            RASPUNS = cntA;

            return 1;
        }
        else{
            return 0;
        }
    }

    else {
        return 0;
    }
}

/*
    (TIMP - Z * timp[i].A)
    ramas pentru a bea din laptele b
    din care bea un litru in timp[i].B secunde

    (TIMP - Z * timp[i].A) div timp[i].B litri apuca sa bea

    pt v[i][Ca] stiu sigur ca am o submultime ce contine doar numere dintre [1, i] (nu neaparat pe toate)
    iar fiecare submultime a baut cantitatea Ca de lapte A
    pt fiecare din submultimi, le stiu pe acelea care au cantitatea B de lapte bauta maxim

    TIMP = timpul MAXIM in  care se poate ajunge la o configuratie buna

    daca eu beau pt o persoana un timp tA din laptele A si imi ramane un timp tB = TIMP - tA de baut din laptele B
    acea persoana nu o sa bea neaparat tot timpul din B
    poate sa stea o vreme si fara sa faca nimic
    d-aia apare div

    adica eu ii zic astuia
    tu trebuie sa bei NEAPARAT STRICT cantitatea Z de lapte A
    dupa care bei cat timp mai poti din B
    sa zic ca iti raman 10 secunde sa bei din B
    si tu bei un litru in 4 secunde
    mai bei 2 litri in 8 secunde si dupa aia a fost
    nu bei 2,5 litri!


*/

int main()
{
    fin >> N >> L;

    for(int i = 1; i <= N; i++){
        fin >> timp[i].A >> timp[i].B;
    }


    //caut binar T, pt ca raspuns(T) este monoton

    int lo = 0;
    int hi = LMAX * TIMPMAXIM * 2 + 1;

    while(hi - lo > 1){
        int mid = lo + (hi - lo) / 2;

        int val = valid(mid);
        if(val){
            hi = mid;
        }
        else {
            lo = mid;
        }
    }

    //raspunsul se afla in hi

    fout << hi << "\n";

    int aux = valid(hi); //apelez valid de hi pt a crea v[][]



    for(int i = 1; i <= N; i++){
        fout << cantitate[i][RASPUNS].A << ' ' << cantitate[i][RASPUNS].B << "\n";
    }


    return 0;
}