Cod sursa(job #18458)

Utilizator wefgefAndrei Grigorean wefgef Data 18 februarie 2007 12:17:12
Problema Ghiozdan Scor 0
Compilator cpp Status done
Runda preONI 2007, Runda 2, Clasele 11-12 Marime 2.17 kb
#include <cstdio>
#include <algorithm>
#include <vector>

using namespace std;

#define x first
#define y second
#define mp make_pair
#define pb push_back
#define sz size()

#define Gmax 75005
#define Nmax 20005

int v[201], n, g;
int best[26][Gmax], from[26][Gmax];
int ret[10][Gmax];
int cap, coada, sol;
pair<int, int> Q[Gmax];
vector<int> rez;

void readdata()
{
	freopen("ghiozdan.in", "r", stdin);
	freopen("ghiozdan.out", "w", stdout);
	
	int i, val;
	
	scanf("%d %d", &n, &g);
	for (i = 1; i <= n; ++i)
	{
		scanf("%d", &val);
		v[val]++;
	}
}

void rezolva(int K)
{
	int poz = K/25, i, j, k, stp = 0;
	
	for (i = 0; i <= g; ++i)
		best[0][i] = ret[poz][i];
		
	for (j = K; j < K+25; ++j, ++stp)
	{
		for (i = 0; i < j; ++i)
		{
			cap = 1;
			coada = 0;			
			for (k = i; k <= g; k += j)
			{
				while (coada >= cap && Q[coada].x + (k-Q[coada].y)/j > best[stp][k]) --coada;
				Q[++coada] = mp( best[stp][k], k);
				if ((k-Q[cap].y)/j > v[j]) ++cap;
				best[stp+1][k] = Q[cap].x + (k-Q[cap].y)/j;
			}
		}
	}
	
	for (i = 0; i <= g; ++i)
		ret[poz+1][i] = best[25][i];
}

void recon(int K)
{
	int poz = K/25, i, j, k, stp = 0;
	
	for (i = 0; i <= g; ++i)
		best[0][i] = ret[poz][i];
		
	for (j = K; j < K+25; ++j, ++stp)
	{
		for (i = 0; i < j; ++i)
		{
			cap = 1;
			coada = 0;			
			for (k = i; k <= g; k += j)
			{
				while (coada >= cap && Q[coada].x + (k-Q[coada].y)/j > best[stp][k]) --coada;
				Q[++coada] = mp( best[stp][k], k);
				if ((k-Q[cap].y)/j > v[j]) ++cap;
				best[stp+1][k] = Q[cap].x + (k-Q[cap].y)/j;
				from[stp+1][k] = (k-Q[cap].y)/j;
			}
		}
	}
	
	stp = 25;
	for (j = K+24; j >= K; --j, --stp)	
	{
		for (i = 1; i <= from[stp][sol]; ++i) rez.pb(j);
		sol -= from[stp][sol]*j;
	}
}

void solve()
{
	int i;
	
	for (i = 1; i <= g; ++i)
		ret[0][i] = n+1;
	for (i = 1; i < 200; i += 25)
		rezolva(i);
		
	for (sol = g; sol; --sol)
		if (ret[8][sol] < n+1)
		{
			printf("%d %d\n", sol, ret[8][sol]);
			break;
		}
	for (i = 1; i > 0; i -= 25)
		recon(i);
	for (i = 0; i < rez.sz; ++i)
		printf("%d\n", rez[i]);
}

int main()
{
	readdata();
	solve();
	return 0;
}