UVALive 2755 Hidden Password(字符串最小表示)

题目大意:给你一个字符串,它可以左移循环,构成 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)一定是最先的起点。
这道题类似后缀数组的方法应该也能做,先把上面那个学了,这个之后再说吧。。。囧

代码如下:

#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;
}


你可能感兴趣的:(UVALive 2755 Hidden Password(字符串最小表示))