题意:

      给你一个最长100W的串,然后让你找到最小同构子串,还有最大同构子串的下标,最小同构子串就是把字符串连接成一个环,然后选择一个地方断开,得到的一个ASCII最小的子串(求最大同理),得到两个下标之后还要求两个数,就是最小子串出现的次数,还有最大子串出现的次数,就是所有循环移位后的到的len个子串中最小子串出现了多少次?

思路:

      求最小和最大小标这个可以用最小表示法来求(求最大就是把最小表示法稍微改一下),而求出现次数可以用KMP来求,出现次数等于最大周期数,为什么等于这个可以这样想

abcabcabc 循环移位 bcabcabca 继续 cabcabcab 继续 abcabcabc三次就得到一个一样的了,那么也就是说这个串中的任何循环移位串只要三次就会出现一样的,本来总个数是len,每三个一样是不是就是每个串出现len/3,这个三是不是就是我们KMP里面说的那个最小循环节。len/最小循环节 不就是最小循环节的周期数吗? so..直接KMP搞定次数,任何串出现的次数都是一样的,最后再返回来说下最小表示法。

最小表示法可以直接求出来自小的(或者是最大的)循环移位串的首字母是的下标,

比如dabc的小标就是2(从1开始)

核心代码很短

int GetMinId(char *str)

{

    int i = 0 ,j = 1 ,k = 0;

    while(i < len && j < len && k < len)

    { 

        int t = str[(i+k)%len] - str[(j+k)%len];

        if(!t) ++k;

        else 

        {

            t > 0 ? i = i + k + 1 : j = j + k + 1;

            if(i == j) j ++;

            k = 0;

        } 

    }

    return i < j ? i : j;

}

可以这么理解,先定义两个变量i,j表示的都是前缀的下标,每次更新的时候我们把不满足的下标往后更新,就是往后+,最后得到前面的那个小的就是答案,关键是为什么?

我是这样想的

首先核心就是

if(t > 0) i = i + k + 1;

else j = j + k + 1;

这个地方是什么情况,比如i代表的串是 abcd  j代表的串是abca此时的k肯定是3那么t>0这个时候i直接跳到d的后面,也就是i = i + k + 1,就是默认之间的都肯定不是答案,这个是关键,为什么之间的bcd都肯定不是答案的起点呢,原因是abcd 和abca比较的时候到k=3的时候发现不相等了,那么之前的一定是相等的,那么也就是说i的串的a和d之间的bcd当串首字母的时候肯定会被j的串abca中的bc当首字母比下去,因为bcd<bca cd< ca d < a就是没有必要再比较了,这个一开始可能很不容易理解,但是仔细想想会明白的,我说的是我自己的理解,也有可能有错误,还有就是提示一点,如果实在理解不了这个方法可以先写一个暴力的,然后在想,我就是这么干的,顺便给一个暴力的代码吧,暴力的很多时候也可以过题目,只不过要看数据。

int GetMinId(char * str)

{

   int len = stelen(str);

   int i = 0 ,j = 1 , k = 0;

   while(i < len && j < len && k < len)

   {

       int t = str[(i+k)%len] - str[(j+k)%len];

       if(!t) ++k;

       else 

       {

          if(t > 0) i = j;

          j ++;

          k = 0;

        }

   }

   return i;

}

下面是hdu3374代码

#include<stdio.h>

#include<string.h>

#define N 1000000 + 10

char str[N];

int next[N];

void GetNext(int m ,char *str)

{

    int j = 0 ,k = -1;

    next[0] = -1;

    while(j < m)

    {

        if(k == -1 || str[j] == str[k])

        next[++j] = ++k;

        else k = next[k];

    }

}

int GetMinId(int len ,char *str)

{

    int i = 0 ,j = 1 ,k = 0;

    while(i < len && j < len && k < len)

    {

        int t = str[(i+k)%len] - str[(j+k)%len];

        if(!t) ++k;

        else

        {

            t > 0 ? i = i + k + 1 : j = j + k + 1;

            if(i == j) j ++;

            k = 0;

        }

    }

    return i < j ? i : j;

}

int GetMaxId(int len ,char *str)

{

    int i = 0 ,j = 1 ,k = 0;

    while(i < len && j < len && k < len)

    {

        int t = str[(i+k)%len] - str[(j+k)%len];

        if(!t) ++k;

        else

        {

            t < 0 ? i = i + k + 1 : j = j + k + 1;

            if(i == j) j ++;

            k = 0;

        }

    }

    return i < j ? i : j;

}

int main ()

{

    int len;

    while(~scanf("%s" ,str))

    {

        len = strlen(str);

        GetNext(len ,str);

        int max = GetMaxId(len ,str) + 1;

        int min = GetMinId(len ,str) + 1;

        int c;

        if(next[len] && len % (len - next[len]) == 0)

        c = len / (len - next[len]);

        else c = 1;

        printf("%d %d %d %d\n" ,min ,c ,max ,c);

    }

    return 0;

}

hdu3374最小表示法+KMP的更多相关文章

  1. Hdu 5442 Favorite Donut (2015 ACM/ICPC Asia Regional Changchun Online 最大最小表示法 + KMP)

    题目链接: Hdu 5442 Favorite Donut 题目描述: 给出一个文本串,找出顺时针或者逆时针循环旋转后,字典序最大的那个字符串,字典序最大的字符串如果有多个,就输出下标最小的那个,如果 ...

  2. HDU-3374-String Problem(最小表示法, KMP)

    链接: https://vjudge.net/problem/HDU-3374 题意: Give you a string with length N, you can generate N stri ...

  3. hdu3374 最大最小表示法 +kmp

    #include <iostream> #include <algorithm> #include <string.h> #include <cstdio&g ...

  4. 【HDU3374】 String Problem (最小最大表示法+KMP)

    String Problem Description Give you a string with length N, you can generate N strings by left shift ...

  5. hdu3374 String Problem KMP+最大最小表示法

    Give you a string with length N, you can generate N strings by left shifts. For example let consider ...

  6. hdu3374 kmp+最小表示法

    Give you a string with length N, you can generate N strings by left shifts. For example let consider ...

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

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

  8. HDU 3374 最小/大表示法+KMP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3374 题意:给定一个串s,该串有strlen(s)个循环同构串,要求输出字典序最小的同构串的下标,字典 ...

  9. hdu5442(2015长春赛区网络赛1006)后缀数组+KMP /最小表示法?

    题意:给定一个由小写字母组成的长度为 n 的字符串,首尾相连,可以从任意一个字符开始,顺时针或逆时针取这个串(长度为 n),求一个字典序最大的字符串的开始字符位置和顺时针或逆时针.如果有多个字典序最大 ...

随机推荐

  1. 关于MarkDown语法

    Markdown语法 码云笔记链接:https://gitee.com/out_of_zi_wen/practical-experience/blob/master/Markdown%E8%AF%AD ...

  2. Springboot的监控

    目录 Micrometer 计数器 仪表 摘要 计时器 Prometheus grafana 保存后我们就能在dashboard上看得我我们的监控指标了参考 Spring Boot有个子项目Sprin ...

  3. 2018.8.30 nowcoder oi赛制测试1

    2018.8.30 nowcoder oi赛制测试1 普及组难度,发现了一些问题 A 题目大意:求斐波那契数列\(f(k-1)f(k+1)-f(k)^2\),范围极大 打表可得规律 其实是卡西尼恒等式 ...

  4. 输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

    题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入描述: 输 ...

  5. 2019 GDUT Rating Contest I : Problem C. Mooyo Mooyo

    题面: C. Mooyo Mooyo Input file: standard input Output file: standard output Time limit: 1 second Memory ...

  6. python2 虚拟环境

    1.安装virtualenv pip install virtualenv 2.创建虚拟环境 virtualenv 虚拟环境名称  3.激活虚拟环境 source 虚拟环境目录/bin/activat ...

  7. Go 语言入门教程,共32讲,6小时(已完结)

    Go语言入门教程,共32讲,6小时(完结) 在B站:https://www.bilibili.com/video/BV1fD4y1m7TD/

  8. Mybatis日志源码探究

    一.项目搭建 1.pom.xml <dependencies> <dependency> <groupId>log4j</groupId> <ar ...

  9. WPF3D立方体图形展开动画思路

    WPF3D立方体图形展开动画 效果图: 规定: 立方体中心为(000),棱长为2,则(111)(-1-1-1)等1,-1三维组合的八个点为其顶点 坐标系: 补充: WPF 3D 分为中心对称旋转(Ro ...

  10. Android Studio 如何运行单个activity

    •写在前面 调试界面运行单个 Activity 可节省编译整个项目的时间提高效率: 本着提高效率的角度,特地上网百度相关知识: •解决方法 首先,在 AndroidManifest.xml 文件中,找 ...