Cod sursa(job #163531)

Utilizator mugurelionutMugurel-Ionut Andreica mugurelionut Data 22 martie 2008 14:43:10
Problema Vanatoare Scor 45
Compilator cpp Status done
Runda preONI 2008, Runda Finala, Clasele 11-12 Marime 4.41 kb
#include <stdio.h>
#include <string.h>

#define NMAX 16
#define INF 666

int xxx[1 << NMAX], vmin[1 << NMAX], chosen[1 << NMAX];
long long c[NMAX + 3], v[NMAX + 3];
int sel[NMAX + 3], bit[NMAX + 3];
int i, j, k, N, ok, subset, subset2, subset3, first, submax, nsel, limsubset2; 
long long T, Tll, vi, x, xv, y, p, q, ca, cb, d, d2, vaux;

void ExtendedEuclid(long long a, long long b)
{
	if (a % b == 0)
	{
		d = b;
		ca = 0;
		cb = 1;
	}
	else
	{
		ExtendedEuclid(b, a % b);

		vaux = ca;
		ca = cb;
		cb = vaux - cb * (a / b);
	}
}

long long NormalEuclid(long long a, long long b)
{
	if (a % b == 0) return b;
	else return NormalEuclid(b, a % b);
}

inline void computeXXX(void)
{
	if (subset == 0)
	{
		xxx[subset] = 0;
		return;
	}

	x = -1;
	ok = 1;

	for (i = 1; i <= N; i++)
		if (sel[i])
		{
			if (x < 0)
				x = c[i], y = v[i];
			else
			{
				if ((x >= c[i]) && (x % v[i] == c[i]))
				{
					// actualizeaza y-ul
					if (y > T)
						y = -1;
					else
					{
						d2 = NormalEuclid(y, v[i]);
						y = (y / d2) * v[i];
					}

					continue;
				}

				if (y > T || y < 0)
				{
					ok = 0;
					break;
				}

				// x trebuie incrementat cu un multiplu de y => x + k*y = c[i] (mod v[i])
				// k*y = (c[i] - x) (mod v[i])
				xv = x % v[i];
				q = (c[i] - xv + v[i]) % v[i];
				p = y % v[i];

				// k * p = q (mod v[i])  =>  k = p^(-1) * q (mod v[i]) => calculam p^(-1)
				ExtendedEuclid(p, v[i]);
				// acum avem: ca * p + cb * v[i] = d

				d2 = NormalEuclid(q, v[i]);

				if (d2 != d)
				{
					ok = 0;
					break;
				}

				p /= d; q /= d; vi = v[i] / d;
				// acum avem: ca * p + cb * vi = 1 => p^(-1) = ca => k = ca * q (mod vi)

				ca %= vi;
				ca = (ca + vi) % vi;
				k = (ca * q) % vi;
				x += k * y;

				if (x > T)
				{
					ok = 0;
					break;
				}

				// actualizeaza y-ul
				if (y > T)
					y = -1;
				else
				{
					d2 = NormalEuclid(y, v[i]);
					y = (y / d2) * v[i];
				}
			}
		}

	if (ok && x <= T)
		xxx[subset] = (int) x;
	else
		xxx[subset] = -1;

	//printf("%d -> %d (%lld)\n", subset, xxx[subset], x);
}

void bktDP2(int niv)
{
	if (niv > N)
	{
		if (subset2 > 0 && xxx[subset2] >= 0 && vmin[subset - subset2] + 1 < vmin[subset])
		{
			vmin[subset] = vmin[subset - subset2] + 1;
			chosen[subset] = subset2;
		}
	}
	else
	{
		bktDP2(niv + 1);
	
		if (sel[niv])
		{
			subset2 |= bit[niv];
			bktDP2(niv + 1);
			subset2 ^= bit[niv];
		}
	}
}

int main()
{
	// preprocesare
	bit[1] = 1;
	for (i = 2; i <= NMAX; i++)
		bit[i] = bit[i - 1] * 2;

	// read input data
	freopen("vanatoare.in", "r", stdin);
	
	scanf("%d %lld", &N, &T);

	for (i = 1; i <= N; i++)
		scanf("%lld %lld", &c[i], &v[i]);

	// compute xxx
	memset(sel, 0, sizeof(sel));
	submax = (1 << N) - 1;
	for (subset = 0; subset <= submax; subset++)
	{
		memset(sel, 0, sizeof(sel));
		for (i = 1; i <= N; i++)
			if (subset & bit[i])
				sel[i] = 1;

		computeXXX();
	}	

	// compute vmin - Dynamic Programming in O(3^N) time
	for (subset = 0; subset <= submax; subset++)
	{
		memset(sel, 0, sizeof(sel));
		nsel = 0;

		for (i = 1; i <= N; i++)
			if (subset & bit[i])
				sel[i] = 1,
				nsel++;

		if (subset == 0)
		{
			vmin[subset] = 0;
			continue;
		}

		vmin[subset] = N + 1;

		if (xxx[subset] >= 0)
		{
			vmin[subset] = 1;
			chosen[subset] = subset;
			continue;
		}

		limsubset2 = (1 << nsel) - 1;
		for (subset3 = limsubset2; subset3 >= 1; subset3--)
		{
			if (vmin[subset] == 2)
				break;

			// compute subset2 from subset and subset3
			subset2 = 0;
			j = 0;
			for (i = 1; i <= N; i++)
				if (sel[i])
				{
					j++;
					if (subset3 & bit[j])
						subset2 |= bit[i];
				}

			//printf("%d -> %d\n", subset, subset2);

			if (subset2 > 0 && xxx[subset2] >= 0 && vmin[subset - subset2] + 1 < vmin[subset])
			{
				vmin[subset] = vmin[subset - subset2] + 1;
				chosen[subset] = subset2;
			}
		}

		//bktDP2(1);
	}

	// afisaza solutia
	freopen("vanatoare.out", "w", stdout);
	
	subset = (1 << N) - 1;
	printf("%d\n", vmin[subset]);

	//fprintf(stderr, "done\n");

	first = 1;
	while (subset > 0)
	{
		//fprintf(stderr, "%d -> chosen=%d\n", subset, chosen[subset]);

		if (!first)
			printf(" ");

		printf("%d", xxx[chosen[subset]]);
		subset -= chosen[subset];

		first = 0;
	}

	printf("\n");

	return 0;
}