题目传送门
题意:
字符串
初始是空串。给你一个字符串
,可以选择从串首或串尾拿走一个字符,把这个字符拼接到 的尾部。输出最小字典序的
。数据范围:字符串长度不超过
。题解:
当前串首和串尾的字符不同,那么选择字典序小的那个字符就好了。
如果串首和串尾的字符相同,设串首字符是
,串尾字符是 。我们需要比较内层字符的大小,即比较
和 的大小。如果还相同,那就继续向内层比较,直到找到不同的字符,如果一直相同,那选串首和选串尾是一样的。
暴力做是
。因为每次选字符时要向内层比较的次数是 。选 次那就是 。考虑后缀数组优化。
我们把
的正序和 的倒序拼接成字符串 。举例子:
,那么 。模拟一遍就知道是怎么优化的了。
字符串下标从
开始,初始时 。现在
,然后我们比较 和 的大小关系。其实我们就是在比较
和 的大小关系。这个后缀数组预处理后,就可以 比较了。时间复杂度:
。感受:
想不到用后缀数组。
并且题面的数据范围是错的。我开50W一直RE。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e6 + 5 ;
int rk[maxn << 1] , sa[maxn << 1] , height[maxn << 1] ;
int tmp[maxn << 1] , cnt[maxn] ;
char c[15] , s[maxn << 1] ;
void suffixarray(int n , int m)
{
n ++ ;
for(int i = 0 ; i < n * 2 + 5 ; i ++)
rk[i] = sa[i] = height[i] = tmp[i] = 0 ;//开2 倍空间
for(int i = 0 ; i < m ; i ++) cnt[i] = 0 ;
for(int i = 0 ; i < n ; i ++) cnt[rk[i] = s[i]] ++ ;
for(int i = 1 ; i < m ; i ++) cnt[i] += cnt[i - 1] ;
for(int i = 0 ; i < n ; i ++) sa[-- cnt[rk[i]]] = i ;
for(int k = 1 ; k <= n ; k <<= 1)
{
int j = 0 ;
for(int i = 0 ; i < n ; i ++)
{
j = sa[i] - k ;
if(j < 0) j += n ;
tmp[cnt[rk[j]] ++] = j ;
}
sa[tmp[cnt[0] = 0]] = j = 0 ;
for(int i = 1 ; i < n ; i ++)
{
if(rk[tmp[i]] != rk[tmp[i - 1]]
|| rk[tmp[i] + k] != rk[tmp[i - 1] + k])
cnt[++ j] = i ;
sa[tmp[i]] = j ;
}
memcpy(rk , sa , n * sizeof(int)) ;
memcpy(sa , tmp , n * sizeof(int)) ;
if(j >= n - 1) break ;
}
height[0] = 0 ;
for(int i = 0 , k = 0 , j = rk[0] ; i < n - 1 ; i ++ , k ++)
while(~k && s[i] != s[sa[j - 1] + k])
height[j] = k -- , j = rk[sa[j] + 1] ;
}
int main()
{
int len ;
scanf("%d" , &len) ;
getchar() ;
for(int i = 0 ; i < len ; i ++)
{
s[i] = getchar() ;
getchar() ;
}
for(int i = 0 ; i < len ; i ++)
s[2 * len - i - 1] = s[i] ;
suffixarray(2 * len , 200) ;
int l = 0 , r = len - 1 ;
int cnt = 0 ;
while(l <= r)
{
if(s[l] < s[r]) printf("%c" , s[l]) , l ++ ;
else if(s[r] < s[l]) printf("%c" , s[r]) , r -- ;
else
{
if(rk[l] < rk[2 * len - 1 - r]) printf("%c" , s[l]) , l ++ ;
else printf("%c" , s[r]) , r -- ;
}
cnt ++ ;
if(cnt % 80 == 0) printf("\n") ;
}
printf("\n") ;
}
来源:CSDN
作者:敲代码的欧文
链接:https://blog.csdn.net/Irving0323/article/details/104443597