Cod sursa(job #50379)

Utilizator scapryConstantin Berzan scapry Data 7 aprilie 2007 16:44:42
Problema Xor Max Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.81 kb
#include <assert.h>
#include <stdio.h>

enum { maxn = 100001, maxd = 21 };

int n, p[maxn];
int depth, mask;
int leaf, tab[maxd], restab[maxd];
int result; //for damnlies() / find()
int ans, start, end;

int news; //mem stats

struct ls
{
	int n;
	ls *next;
} *position; //for damnlies() / find()

struct item
{
	ls *pos; //only if leaf
	item *zero, *one;
} root;

void fill_tab(int val)
{
	for(int i = 0; i < depth; i++) {
		if(val & (1 << i)) tab[i] = true;
		else tab[i] = false;
	}
}

void add(item *p, int pos)
{
	assert(p != NULL);
	assert(pos >= 0);

	item **kid;
	if(tab[pos]) kid = &(p->one);
	else kid = &(p->zero);

	if(*kid == NULL) {
		(*kid) = new item;
		(*kid)->zero = NULL;
		(*kid)->one = NULL;
		(*kid)->pos = NULL;

		news++;
	}

	if(pos == 0) {
	       ls *tmp = new ls;
	       tmp->n = leaf;
	       tmp->next = (*kid)->pos;
	       (*kid)->pos = tmp;
	}
	else add(*kid, pos - 1);
}

inline void trie_add(int num, int pos)
{
	fill_tab(num);

	leaf = pos;
	add(&root, depth - 1);
}

void find(item *p, int pos)
{
	assert(p != NULL);

	if(pos == -1) {
		assert(p->pos != NULL);
		assert(p->zero == NULL);
		assert(p->one == NULL);
		
		position = p->pos;
		result = 0;

		for(int i = 0; i < depth; i++)
			if(restab[i]) result |= 1 << i;
	}
	else {
		assert(pos >= -1);

		if(p->zero && p->one) {
			if(tab[pos]) {
				restab[pos] = 1;
				find(p->one, pos - 1);
			}
			else {
				restab[pos] = 0;
				find(p->zero, pos - 1);
			}
		}
		else if(p->zero) {
			restab[pos] = 0;
			find(p->zero, pos - 1);
		}
		else {
			assert(p->one);

			restab[pos] = 1;
			find(p->one, pos - 1);
		}
	}
}

inline void damnlies(int query) //searches the trie for the best match
{	
	fill_tab(query);

#ifndef NDEBUG
	result = -2;
	position = NULL;
#endif

	find(&root, depth - 1);

	assert(result != -2);
	assert(position != NULL);
}

int main()
{
	int i, max = 0, x;
	FILE *f = fopen("xormax.in", "r");
	if(!f) return 1;

	fscanf(f, "%d", &n);
	for(i = 0; i < n; i++) {
		fscanf(f, "%d", &p[i]);
		if(p[i] > max) max = p[i];
	}

	for(depth = maxd; depth; depth--)
		if((1 << (depth - 1)) <= max) break;
	if(depth == 0) depth = 1; //ugly fix
	mask = (1 << depth) - 1;

	fclose(f);
	f = fopen("xormax.out", "w");
	if(!f) return 1;

	trie_add(0, -1);
	x = 0;
	for(i = 0; i < n; i++) {
		x ^= p[i];
		trie_add(x, i);
	}

	ans = -1; //zero is a valid answer and we must find it if it's the best
	x = 0;
	for(i = 0; i < n; i++) {
		x ^= p[i];
		damnlies((~x) & mask);

		if((x ^ result) > ans) {
			max = -3;

			for(ls *p = position; p; p = p->next)
				if(p->n > max && p->n < i) max = p->n;

			//printf("i %d max %d\n", i, max);

			if(max != -3) {
				ans = x ^ result;
				start = max;
				end = i;

				//printf("ans %d start %d end %d\n", ans, start, end);
			}
		}
	}

	assert(ans != -1);

	fprintf(f, "%d %d %d\n", ans, start + 2, end + 1);
	fclose(f);
	return 0;
}