Cod sursa(job #163464)

Utilizator mugurelionutMugurel-Ionut Andreica mugurelionut Data 22 martie 2008 12:26:44
Problema Vanatoare Scor 45
Compilator cpp Status done
Runda preONI 2008, Runda Finala, Clasele 11-12 Marime 3.79 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], v[NMAX];
int sel[NMAX], bit[NMAX];
int i, j, k, N, ok, subset, subset2, first; 
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);
}

void bkt1(int niv)
{
	if (niv > N)
	{
		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);
	}
	else
	{
		sel[niv] = 0;
		bkt1(niv + 1);

		sel[niv] = 1;
		subset |= bit[niv];
		bkt1(niv + 1);
		subset ^= bit[niv];

		sel[niv] = 0;
	}
}


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];
		}
	}
}

void bktDP1(int niv)
{
	if (niv > N)
	{
		if (subset == 0)
		{
			vmin[subset] = 0;
			return;
		}

		//printf("%d\n", subset);
		vmin[subset] = N + 1;

		subset2 = 0;
		bktDP2(1);
	}
	else
	{
		sel[niv] = 0;
		bktDP1(niv + 1);

		sel[niv] = 1;
		subset |= bit[niv];
		bktDP1(niv + 1);
		subset ^= bit[niv];

		sel[niv] = 0;
	}
}

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));
	subset = 0;
	bkt1(1);

	// compute vmin - Dynamic Programming in O(3^N) time
	memset(sel, 0, sizeof(sel));
	subset = 0;
	bktDP1(1);

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

	first = 1;
	while (subset > 0)
	{
		if (!first)
			printf(" ");

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

		first = 0;
	}

	printf("\n");

	return 0;
}