hdu-3374(kmp+最小表示法)

题意:给你一个字符串,这个字符串我们可以把把他变成n个字符串按照以下规则:将当前字符串第一个放到字符串最后一位,字符串的下标依次向前推一位,比如:s[1] s[2 ]s[3] s[4]->s[2 ]s[3] s[4] s[1]...,然后问你字典序最小的和字典序最大的字符串在这n个字符串中的位置

解题思路:首先判定是否是循环串,然后用最小表示法和最大表示法来找出对应的位置,最小表示法可以找出比如一个环形的字符串,找出某个字符开始,然后这个字符串字典序最小;

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
char t[1005000];
int next1[1005000];
int tlen;
void get_next()
{
    int j=0,k=-1;next1[0]=-1;
    while(j<tlen)
    {
        if(k==-1||t[j]==t[k])
            next1[++j]=++k;
        else
            k=next1[k];
    }
}
int get_minstring(char *s)
{
    int len = strlen(s);
    int i = 0, j = 1, k = 0;
    while(i<len && j<len && k<len)
    {
        int t=s[(i+k)%len]-s[(j+k)%len];
        if(t==0)
            k++;
        else
        {
            if(t > 0)
                i+=k+1;
            else
                j+=k+1;
            if(i==j) j++;
            k=0;
        }
    }
    return min(i,j);
}
int get_maxstring(char *s)
{
    int len = strlen(s);
    int i = 0, j = 1, k = 0;
    while(i<len && j<len && k<len)
    {
        int t=s[(i+k)%len]-s[(j+k)%len];
        if(t==0)
            k++;
        else
        {
            if(t > 0)
                j+=k+1;
            else
                i+=k+1;
            if(i==j) j++;
            k=0;
        }
    }
    return min(i,j);
}
int main()
{
    while(scanf("%s",t)!=EOF)
    {
        tlen=strlen(t);
        get_next();
        int minn=get_minstring(t);
        int maxx=get_maxstring(t);
        int l=tlen-next1[tlen];
        if(tlen%l==0&&l!=0)
        {
            printf("%d %d %d %d\n",minn+1,tlen/l,maxx+1,tlen/l);
        }
        else
        {
            printf("%d 1 %d 1\n",minn+1,maxx+1);
        }
    }
}

  

posted @ 2018-08-19 00:15  荒岛的龟  阅读(296)  评论(0编辑  收藏  举报