HDU 3374 String 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

题意:一个长度为n的字符串,通过每次循环移位可以得到n个字符串,那么现在需要输出字典序最小的那个字符串出现的位置及其出现的次数,还有字典序最大的字符串出现的最早位置及其出现的次数,新的方法(最大最小表示)。

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

const int N=1e6+10;

char s[N*2], a[N]; ///s存放两个a字符串,供循环移位时需要
int Next[N], la;

void Getnext() ///这个Next数组存放a的Next值
{
    int i = 0, j = -1;

    Next[0] = -1;

    while (i <= la)
    {
        if (j == -1 || a[i] == a[j])
        {
            i++;
            j++;

            Next[i] = j;
        }
        else j = Next[j];
    }
}

int GetMin() ///求出字典序最小的字符串最早出现的位置
{
    int i = 0, j = 1, k; ///这里i!=j,可以将s[i+k]和s[j+k]分别看做两个字符串的首字符(相当于在判断两个字符串的大小)

    while (i < la && j < la)
    {
        k = 0; ///k记录字符相等的个数

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

        if (k == la) break; ///若是la个字符都相等,那么可以确定两个字符串都是最小的,已经找到最小,停止查找

        if (s[i+k] > s[j+k]) ///因为是求最小的,所以大的那个下标要后移,而小的值不变(类似求最小值,一直更新)
        {
            if (i+k > j) i = i+k+1;
            else i = j+1;
        }
        else
        {
            if (j+k > i) j = j+k+1;
            else j = i+1;
        }
    }

    return min(i, j); ///因为要最早,所以求最小值
}

int GetMax() ///求出字典序最大的字符串最早出现的位置
{
    int i = 0, j = 1, k;

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

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

        if (k == la) 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 ()
{
    int x, Time, Miid, Maid; ///x记录循环节的长度,Time记录出现的次数

    while (scanf("%s", a) != EOF)
    {
        strcpy(s, a);
        strcat(s, a);
        la = strlen(a);

        Getnext();

        x = la - Next[la];
        Time = la / x; ///可以得出最小值和最大值出现次数都为循环节的个数

        Miid = GetMin();
        Maid = GetMax();

        printf("%d %d %d %d\n", Miid+1, Time, Maid+1, Time); ///因为下标都是从0开始的,所以要加1
    }

    return 0;
}
时间: 2024-10-05 00:18:41

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

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 String Problem (KMP+最大最小表示)

转载请注明出处,谢谢http://blog.csdn.net/acm_cxlove/article/details/7854526       by---cxlove 题目:输出最大最小表示是从哪一位开始,而且输出数量 http://acm.hdu.edu.cn/showproblem.php?pid=3374 数量好求,肯定是字符串的循环节,循环节可以直接通过KMP的Next数组得到.这个和yobobobo曾经研究过半天.. 对于最大最小表示法,就是将字符串不断旋转,得到字典序最大或者最小的.

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

hdu 5772 String problem(最大权闭合图)

题目链接:hdu 5772 String problem 题意: 给你一个字符串,只含有数字. 你需要选择出一个子序列,使得这个子序列的权值最大. 这个子序列如果这个数字第一次出现就ans-=bx,否则就-=ax 然后如果第i个字符和第j个字符都在子序列里面,那么ans+=w[i][j] 问你最大ans是多少 官方题解: 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace

HDU 3374 String Proble

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

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

题目大意:有一个字符串长度为N的字符串,这个字符串可以扩展出N个字符串,并且按照顺序编号,比如串  ” SKYLONG “ SKYLONG 1 KYLONGS 2 YLONGSK 3 LONGSKY 4 ONGSKYL 5 NGSKYLO 6 GSKYLON 7 下面这7个都是原串的扩展(循环位移),现在需要求出来字典序最小的和字典序最大的那个串的标号.   输出说明:最小字典序的编号,最小字典序个数,最大字典序编号,最大字典序个数.   分析:以前也遇到过类似的求最小字典序的问题,不过当时不会

hdu P3374 String Problem

今天又在lyk大佬的博客学会了——最小表示法(异常激动发篇题解纪念一下说在前面:给luogu提个建议最小表示法的题太少了,都被hdu抢去了!!! 我们先看一下题目 看完后可以用一个字概括——蒙,两个字——懵逼 在这里我提供题目大意: 输出最大和最小的是从哪一位开始的,同时输出最小循环节的个数. 由于本人懒于写字符串最小表示法,那么我们就来借鉴一下lykkk的优秀总结 看完之后,显然我们就明白了许多 因为题目中让我们同时求出最大和最小的起始位置 所以我们不仅要来一遍最小表示法,还要来一遍最大表示法