String Problem - HDU 3374 (kmp+最大最小表示)

题目大意:有一个字符串长度为N的字符串,这个字符串可以扩展出N个字符串,并且按照顺序编号,比如串 

SKYLONG

SKYLONG 1 
KYLONGS 2 
YLONGSK 3 
LONGSKY 4 
ONGSKYL 5 
NGSKYLO 6 
GSKYLON 7

下面这7个都是原串的扩展(循环位移),现在需要求出来字典序最小的和字典序最大的那个串的标号。

 

输出说明:最小字典序的编号,最小字典序个数,最大字典序编号,最大字典序个数。

 

分析:以前也遇到过类似的求最小字典序的问题,不过当时不会,今天研究了一下发现是有个方法来专门处理这种问题的,就是最大最小表示

,这种方法采用两个指针,表示两个串的开头,如果开头不同直接让字典序大的后移,如果开头相同那么就使用一个计数长度k来往后移动,知道发现s[i+k] != s[j+k] 当然如果k==N那么这两个串都是最小的字典序了,否则,就让值大的那个指针往后移动,直到有指针超过N为止。

 

下面是代码:

==========================================================================================================

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
using namespace std;

const int MAXN = 1e6+7;

char s[MAXN<<1], s1[MAXN];
int Next[MAXN];

void GetNext(char s[], int N)
{
    int i=0, j=-1;
    Next[0] = -1;

    while(i < N)
    {
        if(j==-1 || s[i]==s[j])
            Next[++i] = ++j;
        else
            j = Next[j];
    }
}
int GetMin(char s[], int N)
{///求最小的字典序的开始
    int i=0, j=1;

    while(i<N && j<N)
    {
        int k = 0;

        while(s[i+k] == s[j+k] && k<N)
            k++;

        if(k == N)break;

        if(s[i+k] < s[j+k])
        {
            if(j+k > i)
                j = j+k+1;
            else
                j = i+1;
        }
        else
        {
            if(i+k > j)
                i = i+k+1;
            else
                i = j+1;
        }
    }

    return min(i, j);
}
int GetMax(char s[], int N)
{///求最大的字典序的开始
    int i=0, j=1;

    while(i<N && j<N)
    {
        int k = 0;

        while(s[i+k] == s[j+k])
            k++;

        if(k == N)break;

        if(s[i+k] > s[j+k])
        {
            if(j+k > i)
                j = j+k+1;
            else
                j = i+1;
        }
        else
        {
            if(i+k > j)
                i = i+k+1;
            else
                i = j+1;
        }
    }

    return min(i, j);
}

int main()
{
    while(scanf("%s", s1) != EOF)
    {
        int N = strlen(s1);

        strcpy(s, s1);
        strcat(s, s1);

        GetNext(s, N);
        int circle = N-Next[N], times=1;

        if(N % circle == 0)
            times = N / circle;

        printf("%d %d %d %d\n", GetMin(s, N)+1, times, GetMax(s, N)+1, times);
    }

    return 0;
}
时间: 2024-10-06 00:53:21

String Problem - HDU 3374 (kmp+最大最小表示)的相关文章

String Problem hdu 3374 最小表示法加KMP的next数组

String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1492    Accepted Submission(s): 662 Problem Description Give you a string with length N, you can generate N strings by left shifts.

HDU 3374 (KMP 最小表示法)

String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2442    Accepted Submission(s): 1029 Problem Description Give you a string with length N, you can generate N strings by left shift

hdu 3374 String Problem (kmp+最大最小表示法)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3374 题目大意:输出最大和最小的是从哪一位开始的,同时输出最小循环节的个数. 这里简单介绍对字符串最小表示的方法: (1)  利用两个指针p1, p2.初始化时p1指向s[0], p2指向s[1]. (2)  k = 0开始,检验s[p1+k] 与 s[p2+k] 对应的字符是否相等,如果相等则k++,一直下去,直到找到第一个不同,(若k试了一个字符串的长度也没找到不同,则那个位置就是最小表示位置,

HDU 3374 String Problem (KMP+最大最小表示)

KMP,在有循环节的前提下: 循环节 t = len-next[len], 个数num = len/(len-next[len]); 个人理解,如果有循环节,循环节长度必定小于等于len/2, 换句话说next[len]>=len/2; 对于len%(len-next)!=0的这种情况不讨论,循环节不存在. 下面是假设循环节存在的情况 当次数等于2, 对于abcabc这种情况就不用说了,len = 6, next[len] = 3; 当次数大于2, 对于串a1 a2 a3 a4 a5 a6 a7

hdu 3374 String Problem

String Problem http://acm.hdu.edu.cn/showproblem.php?pid=3374 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3153    Accepted Submission(s): 1272 Problem Description Give you a string with leng

HDU 3374 最小/大表示法+KMP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3374 题意:给定一个串s,该串有strlen(s)个循环同构串,要求输出字典序最小的同构串的下标,字典序最小的出现次数,最大的同构串的下标,字典中最大的出现次数. 思路:对于求循环同构的字典序最小可以用最小表示法求得,最大也是一样.然后设ds为字符串s+s.然后就可以用KMP求最小串在ds出现的次数和最大串出现的次数了. #define _CRT_SECURE_NO_DEPRECATE #inclu

hdu String Problem(最小表示法入门题)

hdu 3374 String Problem 最小表示法 view code#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <string> using namespace std; const int N = 10010; int n; char s[105]; map<

HDOJ3374 String Problem [KMP最小循环节点]+[最小(大)表示法]

String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1442    Accepted Submission(s): 645 Problem Description Give you a string with length N, you can generate N strings by left shifts

HDOJ3374 String Problem 【KMP】+【最小表示法】

String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1512    Accepted Submission(s): 668 Problem Description Give you a string with length N, you can generate N strings by left shifts