• O


    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.OutputOutput 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

    第一次的超时代码
    #include<iostream>
    #include<set>
    #include<map>
    #include<vector>
    #include<string>
    #include<algorithm>
    using namespace std;
    /*
    找一个字符串所有左移产生的字符串中(字符串长度个)
        第一个字典序最小的序列所在位置 和出现次数(字符串长度除以最小循环节长度)
        第一个字典序最大的序列所在位置 和出现次数
    字典序最小或者最大 所在位置 就是向左移动次数
    从前往后遍历 遇到比min小的字符就设置为起点,有相等的就循环比较后面的元素(这里时间复杂度n)
    总的时间复杂度 n2
    */
    #define MAXN 1000001
    char s[MAXN];
    int Next[MAXN];
    void kmp_pre(int l)
    {
        int j,k;
        j=0;k = Next[0] = -1;
        while(j<l)
        {
            if(k==-1||s[j]==s[k])
                Next[++j] = ++k;
            else
                k = Next[k];
        }
    }
    int main()
    {
        while(scanf("%s",s)!=EOF)
        {
            int len = strlen(s),Min=0,Max=0;
            kmp_pre(len);
            for(int i=1;i<len;i++)
            {
                if(s[i]<s[Min])
                    Min = i;
                else if(s[i]==s[Min])
                {
                    for(int j=1;j<len;j++)
                    {
                        if(s[(i+j)%len]<s[(Min+j)%len])
                        {
                            Min = i;
                            break;
                        }
                    }
                }
                if(s[i]>s[Max])
                    Max = i;
                else if(s[i]==s[Max])
                {
                    for(int j=1;j<len;j++)
                    {
                        if(s[(i+j)%len]>s[(Max+j)%len])
                        {
                            Max = i;
                            break;
                        }
                    }
                }
            }
            printf("%d %d %d %d
    ",Min+1,len/(len-Next[len]),Max+1,len/(len-Next[len]));
        }
    }
    #include<iostream>
    #include<set>
    #include<map>
    #include<vector>
    #include<string>
    #include<algorithm>
    using namespace std;
    /*
    找一个字符串所有左移产生的字符串中(字符串长度个)
        第一个字典序最小的序列所在位置 和出现次数(字符串长度除以最小循环节长度)
        第一个字典序最大的序列所在位置 和出现次数
    枚举方法求字典序最大或者最小字符串的算法n方太蠢了,
    以最小为例:原因在于i失配的时候移动距离太小,没有充分利用
    已知条件,比如i-i+k之间的数字显然是大于或者等于i的,所以这些部分没必要再枚举一遍了!直接让i=i+k
    */
    #define MAXN 1000001
    char s[MAXN];
    int Next[MAXN];
    void kmp_pre(int l)
    {
        int j,k;
        j=0;k = Next[0] = -1;
        while(j<l)
        {
            if(k==-1||s[j]==s[k])
                Next[++j] = ++k;
            else
                k = Next[k];
        }
    }
    int FindMin(char s[],int l)
    {
        int i=0,j=1,k=0;
        while(i<l&&j<l&&k<l)
        {
            if(s[(i+k)%l]==s[(j+k)%l])
                k++;
            else if(s[(i+k)%l]>s[(j+k)%l])
            {
                i = i+k+1;
                k = 0;
            }
            else
            {
                j = j+k+1;
                k = 0;
            }
            if(i==j)
                j++;
        }
        return min(i,j);
    }
    int FindMax(char s[],int l)
    {
        int i=0,j=1,k=0;
        while(i<l&&j<l&&k<l)
        {
            if(s[(i+k)%l]==s[(j+k)%l])
                k++;
            else if(s[(i+k)%l]<s[(j+k)%l])
            {
                i = i+k+1;
                k = 0;
            }
            else
            {
                j = j+k+1;
                k = 0;
            }
            if(i==j)
                j++;
        }
        return min(i,j);
    }
    int main()
    {
        while(scanf("%s",s)!=EOF)
        {
            int len = strlen(s);
            kmp_pre(len);
            int Max = FindMax(s,len),Min = FindMin(s,len);
            printf("%d %d %d %d
    ",Min+1,len/(len-Next[len]),Max+1,len/(len-Next[len]));
        }
    }
  • 相关阅读:
    vue双向绑定的时候把遍历的数组转为了字符串,并且再转回去数组进行绑定
    使用for of循环遍历获取的nodeList,配置babel编译,webpack打包之后在iphone5下报错
    iview表单验证不生效问题注意点
    babel配置项目目录支持转换es6语法,引入非项目目录js后,引入Js转换无效
    swiper4自动轮播切换手动触碰后停止踩坑——属性disableOnInteraction
    移动网页广告引入mraid.js使用指南
    react项目和next项目修改默认端口号
    windows安装mongodb服务简洁版教程
    Fiddler抓包手机代理配置
    手机配置代理报错invalid host header
  • 原文地址:https://www.cnblogs.com/joeylee97/p/6686748.html
Copyright © 2020-2023  润新知