题目大意:给你一个字符串,它可以左移循环,构成 n-1 个串,问你这些字符串中字典序最小的是哪个,输出它的首字母在原先串
中的位置,如果有多个,那么就输出第一个出现的,就是位置最小的那个。
思路:看着像后缀数组,尝试着加着一点剪枝敲了一下,果然TLE。。 = =
后来一看,原来这道题的算法很经典,具体参见这篇论文吧: http://wenku.baidu.com/view/452cbcd528ea81c758f578ad.html
然后有一点需要说明,按照这个算法来,两个串找到的匹配位置不一定是最小表示的位置,但是这个位置一定是 <= M(S) 的。
论文里是两个串,这里是一个串,一样的。两个指针i、j,分别指起点,一个0,一个1,然后len表示长度,这里关键就是不匹配时应该加 len,这时
i、j有可能相等,所以这时就if一个 j++,不算,继续找,如果这个时候 i 那个位置是 M(S),那么 i 的位置就不会动。总之,min(i,j)一定是最先的起点。
这道题类似后缀数组的方法应该也能做,先把上面那个学了,这个之后再说吧。。。囧
中的位置,如果有多个,那么就输出第一个出现的,就是位置最小的那个。
思路:看着像后缀数组,尝试着加着一点剪枝敲了一下,果然TLE。。 = =
后来一看,原来这道题的算法很经典,具体参见这篇论文吧: http://wenku.baidu.com/view/452cbcd528ea81c758f578ad.html
然后有一点需要说明,按照这个算法来,两个串找到的匹配位置不一定是最小表示的位置,但是这个位置一定是 <= M(S) 的。
论文里是两个串,这里是一个串,一样的。两个指针i、j,分别指起点,一个0,一个1,然后len表示长度,这里关键就是不匹配时应该加 len,这时
i、j有可能相等,所以这时就if一个 j++,不算,继续找,如果这个时候 i 那个位置是 M(S),那么 i 的位置就不会动。总之,min(i,j)一定是最先的起点。
这道题类似后缀数组的方法应该也能做,先把上面那个学了,这个之后再说吧。。。囧
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 111111;
char str[MAXN<<1];
int main()
{
int _;
scanf("%d",&_);
while(_--)
{
int n;
scanf("%d%s",&n,str);
for(int i = 0;i < n;i++)
str[n+i] = str[i];
str[n+n] = '\0';
int i = 0,j = 1,len = 0;
while(i < n && j < n)
{
if(str[i+len] == str[j+len])
{
len++;
if(len == n)
break;
}
else
{
if(str[i+len] < str[j+len])
j = j+len+1;
else i = i+len+1;
if(i == j) j++;
len = 0;
}
//printf("i = %d,j = %d,len = %d\n",i,j,len);
}
printf("%d\n",min(i,j));
}
return 0;
}