HDU 3374 String Problem(KMP中求最小循環節出現的次數+最大最小表示法)

Problem Description

Give you a string with length N, you can generate N strings by left shifts. For example let consider the string “SKYLONG”, we can generate seven strings:
String Rank
SKYLONG 1
KYLONGS 2
YLONGSK 3
LONGSKY 4
ONGSKYL 5
NGSKYLO 6
GSKYLON 7
and lexicographically first of them is GSKYLON, lexicographically last is YLONGSK, both of them appear only once.
  Your task is easy, calculate the lexicographically fisrt string’s Rank (if there are multiple answers, choose the smallest one), its times, lexicographically last string’s Rank (if there are multiple answers, choose the smallest one), and its times also.

 

Input

  Each line contains one line the string S with length N (N <= 1000000) formed by lower case letters.

 

Output

Output four integers separated by one space, lexicographically fisrt string’s Rank (if there are multiple answers, choose the smallest one), the string’s times in the N generated strings, lexicographically last string’s Rank (if there are multiple answers, choose the smallest one), and its times also.

 

Sample Input

abcder
aaaaaa
ababab

 

Sample Output

1 1 6 1
1 6 1 6
1 3 2 3

 

題意:

首先介紹一下最大最小表示法

比如一個字符串abcde,那麼求該串的同構串中字典序最小的那個就是最小表示法,同構串就是每次將串整體循環移動一位形成的新串。例如前面那個串的同構串有bcdea,cdeab,deabc,eabcd,求其字典序中最小的那個串就是最小表示法,同理可得最大表示法

題意:給你一個字符串,讓你求最小表示法的開始位置(字符串從1開始編號)和最小循環節數量;最大表示法的開始位置(字符串從1開始編號)和最小循環節數量

 

思路:

注意:對於一個字符串的任何同構串,它們的最小循環節雖然不一樣,但最小循環節都是由相同的字母組成的,並且最小循環節的數量是一樣的。

可以以abcabc爲例,其最小循環節abc

同構串:bcabca,其最小循環節bca

同構串:cabcab,其最小循環節cab

同構串:abcabc,其最小循環節abc

 

最小最大表示法:怎麼求最小表示法的開始位置(字符串從0開始編號)和最大表示法的開始位置(字符串從0開始編號);

                             怎麼求最大(小)的子串排第幾

最小最大表示法------時間複雜度O(n)

//最小表示法
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);
}

 

代碼:

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXM=1000017;
char P[MAXM];
int f[MAXM],dp[MAXM];
int m;
void getFail(char *P,int *f)
{
    f[0]=f[1]=0;
    for(int i=1;i<m;i++)
    {
        int j=f[i];
        while(j && P[i]!=P[j]) j=f[j];
        f[i+1] = (P[i]==P[j])? j+1:0;
    }
}
//最小表示法
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",P)!=EOF)
    {
        m=strlen(P);
        getFail(P,f);
        int tt=m-f[m];
        int num=1;
        if(m%tt==0)
        {
            num=m/tt;
        }
        int posmin = get_minstring(P);
        int posmax = get_maxstring(P);
        printf("%d %d %d %d\n",posmin+1,num,posmax+1,num);
    }
    return 0;
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章