Cod sursa(job #519220)

Utilizator savimSerban Andrei Stan savim Data 4 ianuarie 2011 16:01:01
Problema Ghiozdan Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.71 kb
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

#define MAX_N 20010
#define MAX_G 75010
#define inf 1000000000

int n, m;      
int minNr[2][MAX_G], c[2][MAX_G];
int G[MAX_N];
int nr[210], Q[MAX_G];

void work(int st, int dr, int val, int lin) {
	memset(c, 0, sizeof(c));
	for (int i = 1; i <= val; i++)
		c[0][i] = inf;

	//folosesc greutatile st, st + 1 .. dr
	int l = 0;
	for (int i = st; i <= dr; i++) 
		if (nr[i] > 0) {
	    	l = 1 - l;
			for (int j = 1; j <= val; j++)
				c[l][j] = c[1 - l][j];

			for (int j = 1; j <= i; j++) { //lucrez pentru greutatea i, si iau in considerare subsirul j, j + i, j + 2*i...
				int st = 1, dr = 0;

				//initializez deque-ul
				for (int k = j + i * ((val - j) / i), count = 1; k >= 0 && count <= nr[i] + 1; k -= i, count++) {
    				Q[++dr] = k;
					while (dr > st && c[l][Q[dr]] + (k - Q[dr]) / i < c[l][Q[dr - 1]] + (k - Q[dr - 1]) / i) {
                    	Q[dr - 1] = Q[dr];
						dr--;
					}
				}

				for (int k = j + i * ((val - j) / i); k >= i; k -= i) {
                	while (Q[st] >= k)
						st++;
					c[l][k] = min(c[l][k], c[l][Q[st]] + (k - Q[st]) / i); 

					if (k - (nr[i] + 1) * i >= 0) {
						Q[++dr] = k - (nr[i] + 1) * i;
                    	while (dr > st && c[l][Q[dr]] + (k - Q[dr]) / i < c[l][Q[dr - 1]] + (k - Q[dr - 1]) / i) {
                        	Q[dr - 1] = Q[dr];	
							dr--;
						}
					}
				}
			}

			for (int j = 1; j <= val; j++)
				c[1 - l][j] = inf;
		}

	for (int i = 1; i <= val; i++) 
		minNr[lin][i] = c[l][i];
}

void solve(int st, int dr, int val, int step) {
	if (val == 0)
		return;

	if (st == dr) {
		while (val) {
        	val -= st;
			printf("%d\n", st);
		}

    	return;
	}

	memset(minNr, 0, sizeof(minNr));
	work(st, (st + dr) / 2, val, 0);
	work((st + dr) / 2 + 1, dr, val, 1);

	if (step == 1) {
    	int p = val, smax = 0;
		for (int i = 0; i <= val; i++) 
			if (minNr[0][i] != inf) {
	        	while ((i + p > val || minNr[1][p] == inf) && p > 0)
					p--;

				smax = max(smax, i + p);
			}

		val = smax;
	}

	int sol = inf, pos = 0;
	for (int i = 1; i <= val; i++)
		if (minNr[0][i] + minNr[1][val - i] < sol) {
        	sol = minNr[0][i] + minNr[1][val - i];
			pos = i;
		}
	if (minNr[0][val] <= sol) {
    	sol = minNr[0][val];
		pos = val;
	}
	if (minNr[1][val] <= sol) {
    	sol = minNr[1][val];
		pos = 0;
	}

	if (step == 1)
		printf("%d %d\n", val, sol);

	solve(st, (st + dr) / 2, pos, step + 1);
	solve((st + dr) / 2 + 1, dr, val - pos, step + 1);
}

int main() {

	freopen("ghiozdan.in", "r", stdin);
	freopen("ghiozdan.out", "w", stdout);

	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &G[i]);
    	nr[G[i]]++;
	}
	sort(G + 1, G + n + 1);

	solve(1, G[n], m, 1);

	return 0;
}