Pagini recente » Cod sursa (job #3206940) | Cod sursa (job #3286218) | Cod sursa (job #219093) | Cod sursa (job #2892384) | Cod sursa (job #1067556)
/* cea mai comentata sursa din repertoriul personal */
#include <iostream>
#include <cstdio>
#include <deque>
using namespace std;
/* palindrom FTW */
const int MAX = 75057;
const int GMAX = 205;
const int INF = 0x3f3f3f3f;
int N, G, cnt[GMAX];
int dp[2][MAX], D[2][MAX];
deque<int> dq;
void citire() {
freopen("ghiozdan.in", "r", stdin);
freopen("ghiozdan.out", "w", stdout);
cin >> N >> G;
for(int i = 0, A; i < N; i++) {
cin >> A;
cnt[A]++;
}
}
/* vreau sa rezolv o subproblema a problemei initiale */
/* vreau sa obtin cu obiecte care au greutatile cuprinse intre L si R o greutate totala cat mai apropiata de G */
/* seems legit pana aici... congrats Radu! WOOHOO */
void solve(int L, int R, int G) {
/* daca nu am ce greutate sa obtin, why bother? */
//cerr << L << " " << R << " " << G << "\n";
if(!G) return;
/* daca am o singura valoare din care sa aleg, apai logic ca aleg valoarea aia... d'oh */
if(L == R) {
//cerr << "Entered " << L << " EQUALS " << R << "\n";
/* si o tot scad atata cat pot :D */
for(; cnt[L] && G - L >= 0; cnt[L]--, G -= L)
cout << L << "\n";
/* dupa care ies din functie ca "My work here is done" */
return;
}
/* the real deal */
/* O sa vreau sa imi impart problema in doua subprobleme. Una in care dispun de greutatile L...M si alta in care dispun de greutatile M + 1...R */
int M = (L + R) >> 1, now = 0;
/* reinitializare dinamica */
/* dp[i][j] = numarul minim de obiecte de greutate mai mica sau egala cu i de care am nevoie pentru a obtine greutatea j */
dp[0][0] = 0;
for(int i = 1; i <= G; i++)
dp[0][i] = INF;
/* acu fac dinamica in complexitate O(200 * G) */
for(int i = L; i <= R; i++) {
/* Daca nu e, nu e */
if(!cnt[i]) continue;
now = 1 - now;
/* rezolv separat pentru fiecare categorie de resturi la impartirea cu i */
for(int R = 0; R < i; R++) {
while(!dq.empty()) dq.pop_front();
/* parcurg toate variantele posibile cu rest R la impartirea cu i */
for(int j = R, step = 0; j <= G; j += i, step++) {
/* classical deque shit */
int Val = dp[1 - now][j] - step;
while(!dq.empty() && dp[1 - now][ dq.back() ] >= Val) dq.pop_back();
dq.push_back(j);
/* modific valoarea lui dp[1 - now][j] pentru ca altfel step ar influenta rezultatul final si nu e ok... */
dp[1 - now][j] = Val;
dp[now][j] = dp[1 - now][ dq.front() ] + step;
/* prima aparitie a celei de-a doua dinamici :) */
/* D[i][j] - coloana de pe linia M prin care trec ca pe linia i sa ajung pe coloana j */
/* Aici am avut un jeg de bug, considerand ca nu are sens dinamica pentru i < M. Dar daca nu am greutati i > M, eu o lasam necompletata... */
/* Future me, you should be ashamed of this */
D[now][j] = j;
if(i > M) {
D[now][j] = D[1 - now][ dq.front() ];
}
if(dq.front() + i * cnt[i] == j) dq.pop_front();
}
}
}
int ans = 0;
for(int i = G; i; i--)
if( dp[now][i] != INF ) {
ans = i;
break;
}
/* daca ma aflu la primul apel al functiei, ala cu toate greutatile disponibile, afisez rezultatul dinamicii. Celelalte apeluri ale functiei au rol doar in reconstruirea solutiei */
if(L == 1 && R == 200) {
cout << ans << " " << dp[now][ans] << "\n";
}
/* apelez functia mai departe */
solve(L, M, D[now][ans]);
solve(M + 1, R, ans - D[now][ans]);
//cerr << "Exiting " << L << " " << R << " " << G << "\n";
}
int main() {
citire();
solve(1, 200, G);
fclose(stdin); fclose(stdout);
}