Cod sursa(job #18833)

Utilizator wefgefAndrei Grigorean wefgef Data 18 februarie 2007 14:15:56
Problema Ghiozdan Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.28 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[21][Gmax];
int ret[11][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/20, i, j, k, stp = 0;
	
	for (i = 0; i <= g; ++i)
		best[0][i] = ret[poz][i];
	
	
	for (j = K; j < K+20; ++j, ++stp)
	{
		for (i = 0; i < j; ++i)
		{
			cap = 1;
			coada = 0;			
			for (k = i; k <= g; k += j)
			{
				
				if (coada >= cap)
				while (Q[coada].x + (k-Q[coada].y)/j > best[stp][k])
				{
					--coada;
					if (coada < cap) break;
				}				
				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[20][i];
}


void recon(int K)
{
	int poz = K/20, i, j, k, stp = 0;
	
	for (i = 0; i <= g; ++i)
		best[0][i] = ret[poz][i];
		
	for (j = K; j < K+20; ++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;
			}
		}
	}
	
	stp = 20;
	for (j = K+19; j >= K; --j, --stp)	
	{
		for (i = sol; i >= 0; i-= j)
		if (best[stp-1][i] + (sol-i)/j == best[stp][sol])
		{
			for (k = i; k < sol; k += j)
				rez.pb(j);
			sol = i;
			break;
		}
	}
}


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

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