题目要求每次从头或从尾取一个字母,要求最后的结果字典序最小。
本题可以用暴力过,设置两个指针i j,比较s[i] s[j],不同则选小的,相同则再比较s[i+1] s[j-1]。。。。依此类推。
另一种方法是采用后缀数组,将比较的过程优化。先将原来的串正向反向连接起来( abc变成abc#cba),然后利用后缀数组初始化,需要比较的时候利用RMQ来读取不同的字母。
#include <stdio.h>
#include <string.h>
#include <math.h>
#define max(a,b) (a>b?a:b)
const int N = 60100;
const int INF = 1<<30;
int n;
char s[N];
int cnt[N], mem[4][N], *rank, *nrank, *sa, *nsa, h[N];
int d[N][30];
void radix_sort()
{
int i, k;
rank = mem[0];
nrank = mem[1];
sa = mem[2];
nsa = mem[3];
memset( cnt, 0, sizeof(cnt));
memset( mem, 0, sizeof(mem));
for(i = 0; i < n; i++) cnt[s[i]]++;
for(i = 1; i < 256; i++) cnt[i] += cnt[i-1];
for(i = n-1; i >= 0; i--) sa[--cnt[s[i]]] = i;
for(rank[0]=0, i=1; i < n; i++)
{
rank[sa[i]] = rank[sa[i-1]];
if(s[sa[i]]!=s[sa[i-1]]) rank[sa[i]]++;
}
for(k = 1; k<n && rank[sa[n-1]] < n-1; k*=2)
{
for(i = 0; i < n; i++) cnt[rank[sa[i]]] = i+1;
for(i = n-1; i >= 0; i--)
{
if(sa[i]-k>=0)
nsa[--cnt[rank[sa[i]-k]]] = sa[i]-k;
}
for(i = n-k; i < n; i++)
nsa[--cnt[rank[i]]] = i;
/*//
for ( i=0; i<n; i++ )
printf("%d ", nsa[i] );
printf("/n" );
*/
for(nrank[nsa[0]]=0, i=1; i < n; i++)
{
nrank[nsa[i]] = nrank[nsa[i-1]];
if(rank[nsa[i]] != rank[nsa[i-1]]
|| rank[nsa[i]+k] != rank[nsa[i-1]+k])
nrank[nsa[i]]++;
}
int *stemp = rank; rank = nrank; nrank = stemp;
stemp = sa; sa = nsa; nsa = stemp;
}
}
void initRMQ( int *D, int top)
{
int i , j ,k,sk;
for( i = 0 ; i < top ; i ++ )
d[i][0] = i;
for( j = 1 ,k=2; k <= top ; j ++,k <<= 1 )
{
for( i = 0 ; i < top ; i ++ )
{
sk = i+(k>>1) ;
d[i][j] = d[i][j-1] ;
if( sk < top && D[d[i][j]] >= D[d[sk][j-1]] )
d[i][j] = d[sk][j-1] ;
}
}
}
int RMQ( int *D , int i , int j )
{
//int k = log22[j-i+1] ;
int k = int(log(j-i+1.0)/log(2.0)) ;
int k2 = (1 << k)-1;
if( D[d[i][k]] < D[d[j-k2][k]] )
return d[i][k];
else
return d[j-k2][k];
}
void get_lcp_rmq()
{
int i, j, k;
memset( h, 0, sizeof(h));
for (j = 0, i = 0; i < n; i++)
{
if (rank[i] == 0)
h[0] = j = 0;
else
{
k = sa[rank[i]-1];
for (j = max(j-1,0); s[i+j] == s[k+j]; j++);
h[rank[i]] = j;
}
}
initRMQ( h, n );
}
int ln = 0;
void check()
{
if ( ln==80 )
{
printf("/n");
ln = 0;
}
ln++;
}
int main ()
{
// freopen("3623.in","r",stdin);
// freopen("3623.txt","w",stdout);
char tmp[100];
int range;
scanf("%d", &n );
range = n;
int i, j;
for ( i=0; i<n; i++ )
{
scanf("%s", tmp );
s[i] = s[2*n-i] = tmp[0];
}
s[n] = '#';
n = 2*n+1;
s[n++] = 0;
radix_sort();
get_lcp_rmq();
i = 0; j=range-1;
while ( i<=j )
{
if ( s[i]<s[j] )
{
check();
printf("%c", s[i] );
i++;
}
else
{
if ( s[i]>s[j] )
{
check();
printf("%c", s[j] );
j--;
}
else
{
int xa = rank[i];
int xb = rank[2*range-j];
int tt;
if ( xa<xb )
tt = h[RMQ( h, xa+1, xb )];
else
tt = h[RMQ( h, xb+1, xa )];
if ( s[i+tt]<s[j-tt] )
{
check();
printf("%c", s[i] );
i++;
}
else
{
check();
printf("%c", s[j] );
j--;
}
}
}
}
printf("/n" );
}