HDU 3374(最小最大表示法+KMP)

传送门

String Problem

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4445    Accepted Submission(s): 1814

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

题目描述:

    给你一个字符串,让你求出其的最小表示的首个位置以及最大表示的首个位置以及最小最大表示分别出现了多少次。

题目分析:

    这是一个很棒的综合性字符串模板的问题。其中包括了最小表示法、最大表示法的求法以及KMP的运用。

    其中最小表示为n个循环同构字符串中,字典序最小的一个(最大表示为字典序最大的一个)。

    对于最小最大表示,我们可以通过双指针在O(n)的时间内求出。

    对于第二个要求,题目要求我们求出最小最大表示出现的次数,不难发现,他们出现的次数跟等于循环节的个数,我们可以通过KMP的next数组进行求解。时间复杂度同样是O(n)。

代码:

#include <bits/stdc++.h>
#define maxn 2000005
using namespace std;
char str[maxn];
int nextt[maxn];
void get_next(char *a,int len){//求解next数组板子
    int i=0,j=nextt[0]=-1;
    while(i<len){
        while(j!=-1&&a[i]!=a[j]) j=nextt[j];
        nextt[++i]=++j;
    }
}
int get_minn(char *a,int len){//最小表示法板子
    int i=0,j=1;
    for(int i=0;i<len;i++){
        str[i+len]=str[i];
    }
    while(i<len&&j<len){
        int k;
        for(k=0;k<len&&a[k+i]==a[k+j];k++);
        if(k==len) break;
        if(a[k+i]>a[k+j]){
            i=i+k+1;
            if(i==j) i++;
        }
        else{
            j=j+k+1;
            if(i==j) j++;
        }
    }
    return min(i,j);
}
int get_maxx(char *a,int len){//最大表示法板子
    int i=0,j=1;
    for(int i=0;i<len;i++){
        str[i+len]=str[i];
    }
    while(i<len&&j<len){
        int k;
        for(k=0;k<len&&a[k+i]==a[k+j];k++);
        if(k==len) break;
        if(a[k+i]<a[k+j]){
            i=i+k+1;
            if(i==j) i++;
        }
        else{
            j=j+k+1;
            if(i==j) j++;
        }
    }
    return min(i,j);
}
int main()
{
    while(~scanf("%s",str)){
        int len=strlen(str);
        memset(nextt,0,sizeof(nextt));
        get_next(str,len);
        int minn=get_minn(str,len);
        int maxx=get_maxx(str,len);
        int tmp=nextt[len];
        if(len%(len-tmp)!=0){
            cout<<minn+1<<" 1 "<<maxx+1<<" 1"<<endl;
        }
        else{
            cout<<minn+1<<" "<<len/(len-tmp)<<" "<<maxx+1<<" "<<len/(len-tmp)<<endl;
        }
    }
}

 

转载于:https://www.cnblogs.com/Chen-Jr/p/11007237.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值