Cod sursa(job #50360)

Utilizator scapryConstantin Berzan scapry Data 7 aprilie 2007 16:19:13
Problema Xor Max Scor 45
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.51 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, position;
int ans, start, end;

int news; //mem stats
int d;
void pd()
{
	for(int i = 0; i < d; i++) printf(" ");
}

struct item
{
	int 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 = -2;

		news++;
	}

	if(pos == 0) (*kid)->pos = leaf;
	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 != -2);
		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 = -2;
#endif

	find(&root, depth - 1);

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

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;
	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 && position < i) {
			ans = x ^ result;
			start = position;
			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;
}