Cod sursa(job #3336012)

Utilizator iulia_morariuIuli Morariu iulia_morariu Data 23 ianuarie 2026 23:32:51
Problema Ghiozdan Scor 60
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.12 kb
#include <algorithm>
#include <iostream>
#include <fstream>
#include <climits>
#include <vector>
#include <queue>
#include <cmath>
// #include <bits/stdc++.h>
#define in  fin
#define out fout
#define int long long

using namespace std;
using ll = long long;
const int GMAX = 75005, NMAX = 20000;

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

int n, g;
int dp[GMAX][2];
int ult[GMAX][2]; // l-as fi numit r da coincide cu ala din divide
int v[NMAX];
int vf[201]; // minimude201 reference
ll dp1[GMAX];
// ll ult[GMAX], ult_nr[GMAX];

void imparte_si_cucereste(int l, int r, int g_acuma){ // care e modul bun sa fac pe L - R costul g_acuma?
    if(l == r){ // cred ca am lowkey terminat
        int cnt = g_acuma / l; // ca gen de atatea ori il pun
        if(cnt > vf[l]) out << "oh no\n"; // nush ce sa fac daca se intampla asta deci osa sper ca nu se intampla
        for(int i = 0; i < cnt; i++) out << l << '\n';
        return;
    }

    for(int i = 0; i <= g_acuma; i++){
        dp[i][(l - 1) % 2] = INT_MAX;
        ult[i][(l - 1) % 2] = i;
    }
    int m = (l + r) / 2;
    dp[0][0] = 0;
    // cout << "Sunt la ( " << l << " , " << r << " ) g = " << g_acuma << '\n';
    for(int nr = l; nr <= r; nr++){;
        for(int i = 0; i <= g_acuma; i++){
            dp[i][nr % 2] = dp[i][(nr - 1) % 2];
            ult[i][nr % 2] = ult[i][(nr - 1) % 2];
            if(nr == m + 1) ult[i][nr % 2] = i; // ca aici gen incepe tot
        }
        if(vf[nr] == 0) continue;
        // cout << "  -- > incerc sa gatesc cu " << nr << '\n';
        for(int x = g_acuma; x >= 0; x--){
            // cout << "    -- > gatesc cu x = " << x << '\n';
            for(int k = x - nr; k >= 0 && (x - k) / nr <= vf[nr]; k -= nr){
                if(dp[k][(nr - 1) % 2] == INT_MAX) continue;
                if(dp[x][nr % 2] > dp[k][(nr - 1) % 2] - k / nr + x / nr){
                    // cout << "    -- > fur de la k = " << k << " si am " << dp[k][(nr - 1) % 2] - k / nr + x / nr << '\n';
                    dp[x][nr % 2] = dp[k][(nr - 1) % 2] - k / nr + x / nr;
                    ult[x][nr % 2] = ult[k][(nr - 1) % 2];
                }
            }
        }
    }

    int last = g_acuma;
    while(dp[last][r % 2] == INT_MAX) last--;

    cout << "Sunt la ( " << l << " , " << r << " ) si pot sa fac " << last << '\n';
    cout << "impart cu " << ult[last][r % 2] << " si " << last - ult[last][r % 2] << '\n';
    if(last <= 0) return; // nu mai am ce sa continui
    imparte_si_cucereste(l, m, ult[last][r % 2]);
    imparte_si_cucereste(m + 1, r, last - ult[last][r % 2]);
}

signed main(){
    ios_base::sync_with_stdio(false);
    in.tie(NULL);

    in >> n >> g;
    for(int i = 0; i < n; i++){
        in >> v[i];
        vf[ v[i] ]++;
    }

    // initial trebe sa fac dinamica simpla
    // uhhhhhghhhh chiar n-am chef

    for(int i = 0; i <= g; i++) dp[i][0] = dp[i][1] = INT_MAX;

    dp[0][0] = 0;
    for(int nr = 1; nr <= min(200LL, g); nr++){
        // if(vf[nr] == 0) continue;
        for(int i = 0; i <= g; i++) dp[i][nr % 2] = INT_MAX;
        dp[0][nr % 2] = 0;

        for(int r = 0; r < nr; r++){ // restul pt care fac
            deque <int> dq; // poz
            for(int j = 0; r + j * nr <= g; j++){
                // acuma scot gen toate pozitiile care is mai mari ca al meu (ca eu vr minimul)
                while(!dq.empty() && dp[ dq.back() * nr + r ][(nr - 1) % 2] - dq.back() > dp[j * nr + r][(nr - 1) % 2] - j) dq.pop_back(); // get outta here
                // acuma sa scot de la inceput ca e in plus
                dq.push_back(j);
                while(!dq.empty() && dq.front() < j - vf[nr]) dq.pop_front();

                dp[j * nr + r][nr % 2] = dp[dq.front() * nr + r][(nr - 1) % 2] + (j - dq.front());
            }
        }

        // cout << "nr = " << nr << " dp = ";
        // for(int i = 0; i <= g; i++) cout << dp[i][nr % 2] << " ";
        // cout << '\n';
    }

    // cout << "dp : ";
    // for(int i = 0; i <= g; i++) cout << dp[i][0] << " ";
    // cout << '\n';

    int last = g;
    while(dp[last][0] == INT_MAX) last--;
    out << last << " " << dp[last][0] << '\n';
    // imparte_si_cucereste(1, 200, last);
    return 0;
}