Cod sursa(job #163666)

Utilizator gcosminGheorghe Cosmin gcosmin Data 22 martie 2008 14:52:56
Problema Vanatoare Scor 15
Compilator cpp Status done
Runda preONI 2008, Runda Finala, Clasele 11-12 Marime 2.83 kb
#include <stdio.h>

#define LL long long

int N, T;

LL c[1 << 16], v[1 << 16];

int din[1 << 16];
int sol[1 << 16];

char bun[1 << 16];

int vec[20];

int jeg[20];

LL gcd(LL a, LL b, LL &x, LL &y)
{
	if (!b) {
		x = 1; y = 0;
		return a;
	}

	LL x1, y1;
	LL cm = gcd(b, a % b, x1, y1);

	x = y1;
	y = x1 - (a / b) * y1;

	return cm;
}

void reduc(LL &p1, LL c1, LL per)
{
	if (p1 < c1) p1 += per * ((c1 - p1) / per + ((c1 - p1) % per > 0));
	else p1 -= per * ((p1 - c1) / per);
}

LL ABSL(LL x) { return (x < 0) ? -x : x; }

int intersect(LL c1, LL v1, LL c2, LL v2, LL &nc, LL &nv)
{
	LL x, y;
	LL cm, m1;

	if (v1 < 0 || v2 < 0) while (1);
	if (v1 * v2 < 0) while (1);

	if (c1 != c2 && v1 > T && v2 > T) return 0;
	if (v1 < 0 || v2 < 0) return 0;

	if (v1 == v2) cm = v1, x = 1, y = 0;
	else cm = gcd(v1, v2, x, y);
	m1 = v2 / cm;

	if (c1 != c2 && v1 / cm > T / cm) {
//		printf("daaa\n");
		return 0;
	}

	if (c1 == c2) {
		if (v1 == v2) nc = c1, nv = v1;
		else nc = c1, nv = v1 / cm * v2;

		if (nc > T) return 0;

		return 1;
	}

	if ((c2 - c1) % cm) return 0;

	v1 *= (c2 - c1) / cm;

	if (ABSL(v1) > (1LL << 62) / ABSL(x)) {
//		printf("jeeeeg\n");
		return 0;
	}

	LL p1 = c1 + v1 * x;
	LL p2 = c1 + v1 * (x + m1);
	LL per = v1 * m1; if (per < 0) per = -per;

	if (p1 < c1 && per > T) return 0;
	if (p2 < c2 && per > T) return 0;

	reduc(p1, c1, per);
	reduc(p2, c2, per);

	nc = p1 > p2 ? p1 : p2;
	nv = per;

	if (nc > T) return 0;

	return 1;
}

void back(int k, int mask, int i)
{
	if (!bun[mask]) return;

	if (k == vec[0] + 1) {
		if (din[i ^ mask] + 1 < din[i]) {
			din[i] = din[i ^ mask] + 1;
			sol[i] = mask;
		}
		return;
	}

	back(k + 1, mask, i);
	back(k + 1, mask | vec[k], i);
}

int main()
{
	int i, j;

	freopen("vanatoare.in", "r", stdin);
	freopen("vanatoare.out", "w", stdout);

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

	for (i = 1; i <= N; i++) {
		scanf("%lld %lld", &c[1 << (i - 1)], &v[1 << (i - 1)]);
		bun[1 << (i - 1)] = 1;
		din[1 << (i - 1)] = 1;
		sol[1 << (i - 1)] = 1 << (i - 1);
	}

	bun[0] = 1;

	for (i = 1; i < (1 << N); i++) {
		if (!(i & (i - 1))) continue;
	
		// mai intai calculez jegu pentru astea
		
		for (j = 1; j <= i; j <<= 1) if (j & i) break;

		if (bun[i ^ j]) bun[i] = intersect(c[i ^ j], v[i ^ j], c[j], v[j], c[i], v[i]);

		for (vec[0] = 0, j = 1; j <= i; j <<= 1) 
			if (j & i) vec[++vec[0]] = j;

		din[i] = N + 1;
		back(1, 0, i);
	}

	int cur = (1 << N) - 1;
	printf("%d\n", din[cur]);

	while (cur) {
		jeg[++jeg[0]] = c[ sol[cur] ];

		printf("%lld ", c[ sol[cur] ]);
		cur ^= sol[cur];
	}
	printf("\n");

/*	int cc, vv;
	for (i = 1; i <= N; i++) {
		cc = c[1 << (i - 1)]; vv = v[1 << (i - 1)];

		for (j = 1; j <= jeg[0]; j++)
			if (jeg[j] >= cc && (jeg[j] - cc) % vv == 0) {
				printf("%d\n", j);
				break;
			}
		if (j == jeg[0] + 1) break;
	}

	if (i <= N) printf("nuuuuuuuuuuu %d\n", i);
	else printf("a mers\n");
*/
return 0;
}