Cod sursa(job #18615)

Utilizator mugurelionutMugurel-Ionut Andreica mugurelionut Data 18 februarie 2007 12:47:33
Problema Ghiozdan Scor 100
Compilator cpp Status done
Runda preONI 2007, Runda 2, Clasele 11-12 Marime 2.86 kb
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define GMAX 75001
#define WMAX 201
#define INF 666666666
#define OBJMAX 1000000
#define NSKIP 15

int cnt[WMAX], sol[WMAX], dq[GMAX], g[GMAX], li[WMAX], ls[WMAX];
int nmin[2][GMAX], nminstored[(WMAX/NSKIP) + 1][GMAX], pred[NSKIP + 1][GMAX];
int i, j, k, w, N, G, a, c, r, nobj, nmi, gma, w1, w2, gx;

inline void knapsack(int w, int G, int* nmina, int* nminc, int* predc)
{
	for (i = 0; i <= G; i++)
	{
		nminc[i] = nmina[i];

		if (predc != NULL)
			predc[i] = i;
	}

	// considera obiectele de greutate w

	for (i = 0; i < w; i++)
	{
		dq[i] = nmina[i] + OBJMAX;
		li[i] = ls[i] = g[i] = i;
	}

	for (i = w; i <= G; i++)
	{
		r = i % w;

		// scoate din deque daca e in afara intervalului

		while (g[li[r]] < i - w * cnt[w])
			li[r] += w;

		nobj = dq[li[r]] - (OBJMAX - i / w);

		if (nobj < nminc[i])
		{
			nminc[i] = nobj;

			if (predc != NULL)
				predc[i] = g[li[r]];
		}

		// baga in deque pozitia i (nmin[a][i])

		ls[r] += w;
		dq[ls[r]] = nmina[i] + (OBJMAX - i / w);
		g[ls[r]] = i;

		while (ls[r] > li[r] && dq[ls[r]] < dq[ls[r] - w])
		{
			dq[ls[r] - w] = dq[ls[r]];
			g[ls[r] - w] = g[ls[r]];
			ls[r] -= w;
		}
	}
}

void doKnapSack(void)
{
	int x;

	a = c = 0;

	nmin[c][0] = 0;
	nminstored[0][0] = 0;

	for (i = 1; i <= G; i++)
	{
		nmin[c][i] = INF;
		nminstored[0][i] = INF;
	}

	for (w = 1; w < WMAX; w++)
	{
		if (cnt[w] > 0 && w <= G)
		{
			a = c;
			c = 1 - c;

			knapsack(w, G, nmin[a], nmin[c], NULL);
		}

		if (w % NSKIP == 0)
		{
			x = w / NSKIP;

			for (i = 0; i <= G; i++)
				nminstored[x][i] = nmin[c][i];
		}
	}

	nmi = gma = 0;

	for (i = G; i > 0; i--)
		if (nmin[c][i] < INF)
		{
			gma = i;
			nmi = nmin[c][i];
			break;
		}

	// reconstituie solutia - yuck :(

	memset(sol, 0, sizeof(sol));

	for (x = (WMAX - 1) / NSKIP, w2 = WMAX - 1, gx = gma; x >= 0; x--)
	{
		w1 = x * NSKIP;

		//fprintf(stderr, "w2-w1=%d\n", w2 - w1);

		a = c = 0;
		for (i = 0; i <= gx; i++)
			nmin[c][i] = nminstored[x][i];
			
		for (w = w1 + 1; w <= w2; w++)
		{
			if (cnt[w] > 0 && w <= gx)
			{
				a = c;
				c = 1 - c;

				knapsack(w, gx, nmin[a], nmin[c], pred[w - w1 - 1]);
			}
			else
			{
				for (i = 0; i <= gx; i++)
					pred[w - w1 - 1][i] = i;
			}
		}

		w = w2;
		while (w > w1)
		{
			sol[w] = (gx - pred[w - w1 - 1][gx]) / w;
			gx = pred[w - w1 - 1][gx];
			w--;
		}

		w2 = w1;
	}
}

int main()
{
	freopen("ghiozdan.in", "r", stdin);

	scanf("%d %d", &N, &G);

	memset(cnt, 0, sizeof(cnt));

	for (i = 1; i <= N; i++)
	{
		scanf("%d", &j);
		cnt[j]++;
	}

	doKnapSack();

	freopen("ghiozdan.out", "w", stdout);

	printf("%d %d\n", gma, nmi);

	for (i = 1; i < WMAX; i++)
		for (j = 1; j <= sol[i]; j++)
			printf("%d\n", i);

	return 0;
}