USACO DEC07 Problem 'bclgold' Analysis

by Christos Tzamos

This problem can be solved with dynamic programming on the intervals of cows but there is also a simple greedy strategy.

Between the two cows in the edges, you must always pick the cow with the smallest initial letter. If both cows have the same initial letter in order to decide you must look a little bit deeper and check the second cows in the line's edges or the third ones if those are equal and so on until you find two cows that are different. Then you pick the cow from the side of the smallest one.

This process can be summarized as follows.

At any given interval [a,b] with string S([a,b]) you choose:

Cow a if S([a,b]) < rev( S([a,b]) )
Cow b otherwise
where rev(S) is the reverse string e.g. rev("abc") = "cba"

This can be implemented in O(N^2) but we can achieve O(NlogN) by using suffix arrays.

Here are the two implementations:

The O(N^2)
/*
TASK: bcl
LANG: C++
USER: christos
*/
#include<cstdio>

char S[2010],ln=0;

void prnt(char a) {
	if(ln==80) {printf("\n");ln=0;}
	printf("%c",a);ln++;
}

int main() {
	int i,j,N,pi,pj,val;
	freopen("bcl.in" ,"r",stdin );
	freopen("bcl.out","w",stdout);
	scanf("%d",&N);
	for(i=0;i<N;i++) scanf(" %c ",S+i);
	i=0,j=N-1;
	while(i<=j) {
		if(S[i]<S[j])		{prnt(S[i]);i++;}
		else if(S[i]>S[j])	{prnt(S[j]);j--;}
		else {
			pi=i+1;pj=j-1;val=S[i];
			while( pj-pi>1 && S[pi]==S[pj]) {pi++,pj--;}
			if(S[pi]<S[pj]) prnt(S[i]),i++;
			else prnt(S[j]),j--;
		}
	}
	printf("\n");
	return 0;
}

And the O(NlogN)
/*
TASK: bcl
LANG: C++
USER: christos
*/
#include<cstdio>
#include<cstring>
#include<cstdlib>

#define MAXN 500050

char S[2*MAXN];
int N,ln=0;
int o[2][2*MAXN], t[2*MAXN][2];
int A[2*MAXN], B[2*MAXN], C[2*MAXN], D[2*MAXN];

void prnt(char a) {
	if(ln==80) {printf("\n");ln=0;}
	printf("%c",a);ln++;
}

int main() {
	
	int i, j, jj, x, k;
	
	freopen("bcl.in" ,"r",stdin );
	freopen("bcl.out","w",stdout);
	scanf("%d",&N);
	for(i=0;i<N;i++) {
		scanf(" %c ",S+i);
		S[N+i] = S[i];
	}

	memset(A, 0, sizeof(A));
	for (i = 0; i < 2*N; ++i) A[(int)(S[i]-'A')] = 1;
	for (i = 1; i < 26; ++i) A[i] += A[i-1];
	for (i = 0; i < 2*N; ++i) o[0][i] = A[(int)(S[i]-'A')];
	x=0;
	for (j = 0, jj = 1, k = 0; jj < N && k < 2*N; ++j, jj <<= 1) {

		memset(A, 0, sizeof(A));
		memset(B, 0, sizeof(B));

		for (i = 0; i < N; ++i) {
			++A[ t[i][0] = o[x][i] ];
			++B[ t[i][1] = (i+jj<N) ? o[x][i+jj] : 0 ];
		}
		
		for (i = N; i < 2*N; ++i) {
			++A[ t[i][0] = o[x][i] ];
			++B[ t[i][1] = (i-jj>=N) ? o[x][i-jj] : 0 ];
		}

		for (i = 1; i <= 2*N; ++i) {
			A[i] += A[i-1];
			B[i] += B[i-1];
		}

		for (i = 2*N-1; i >= 0; --i)
			C[--B[t[i][1]]] = i;

		for (i = 2*N-1; i >= 0; --i)
			D[--A[t[C[i]][0]]] = C[i];

		x ^= 1;
		o[x][D[0]] = k = 1;
		for (i = 1; i < 2*N; ++i)
			o[x][D[i]] = (k += (t[D[i]][0] != t[D[i-1]][0] || t[D[i]][1] != t[D[i-1]][1]));

	}
	i=0,j=N-1;
	while(i<=j) {
		if(S[i]<S[j])		{prnt(S[i]);i++;}
		else if(S[i]>S[j])	{prnt(S[j]);j--;}
		else if(o[x][i]<o[x][N+j]) {prnt(S[i]);i++;}
		else {prnt(S[j]);j--;}
	}
	printf("\n");
	return 0;
}