zoukankan      html  css  js  c++  java
  • 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]));
        }
    }
  • 相关阅读:
    窗口生效函数UpdateData
    查找内容grep命令
    终止函数 atexit()
    根据名字杀死进程Killall
    修改系统时间为UTC时间
    转 proc文件
    NTP算法
    转载,网线的深刻理解
    js完成密码输入为空,和两次输入不一致
    CSS初步了解
  • 原文地址:https://www.cnblogs.com/joeylee97/p/6686748.html
Copyright © 2011-2022 走看看