HDU3374 String Problem(kmp,最大最小表示法)

来源:互联网 发布:kingroot是什么软件 编辑:程序博客网 时间:2024/05/16 17:34

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

abcderaaaaaaababab

Sample Output

1 1 6 11 6 1 61 3 2 3

思路

先说题意,题意是给一个字符串,然后让你把这个字符串左移,一共有这个字符串长度种表示方法,按照字典序顺序,找出最大的表示是第几次最小的表示是第几次,并且求出他们的出现次数。

输出的四个数字分别为:最小字典序的编号,最小字典序个数,最大字典序编号,最大字典序个数。

分析一下,就知道他们出现的个数其实就是求这个串的循环节的个数,要求编号,我们就通过最大最小表示法来求
关于字符串的最小表示法:
HDU 3374 String Problem (KMP+最大最小表示)
字符串的最小表示法
字符串匹配–最大最小表示法模板
【算法】字符串的最小表示法

代码

#include<cstdio>#include<cstring>#include<string>#include<set>#include<iostream>#include<stack>#include<queue>#include<vector>#include<algorithm>#define mem(a,b) memset(a,b,sizeof(a))#define inf 0x3f3f3f3f#define mod 10000007#define debug() puts("what the fuck!!!")#define ll longlongusing namespace std;const int N=1000000+20;int nxt[N];string s1,s2;void get_next(string s){    int len=s.length();    int j=0,k=-1;    nxt[0]=-1;    while(j<len)        if(k==-1||s[j]==s[k])            nxt[++j]=++k;        else            k=nxt[k];}int get_min(string s){    int len=s.length()/2;    int i=0,j=1;    while(i<len&&j<len)    {        int k=0;        while(s[i+k]==s[j+k]&&k<len)            k++;        if(k==len) break;        if(s[i+k]<s[j+k])        {            if(j+k>i)                j+=k+1;            else                j=i+1;        }        else        {            if(i+k>j)                i+=k+1;            else                i=j+1;        }    }    return min(i,j);}int get_max(string s){    int len=s.length()/2;    int i=0,j=1;    while(i<len&&j<len)    {        int k=0;        while(s[i+k]==s[j+k])            k++;        if(k==len) break;        if(s[i+k]>s[j+k])        {            if(j+k>i)                j+=k+1;            else                j=i+1;        }        else        {            if(i+k>j)                i+=k+1;            else                i=j+1;        }    }    return min(i,j);}int main(){    std::ios::sync_with_stdio(false);    std::cin.tie(0);    while(cin>>s1)    {        int len=s1.length();        get_next(s1);        s2=s1+s1;        int ans=len-nxt[len],cnt=1;        if(len%ans==0)            cnt=len/ans;        cout<<get_min(s2)+1<<" "<<cnt<<" "<<get_max(s2)+1<<" "<<cnt<<endl;    }    return 0;}

优化版代码,可以直接用一个函数求出两个表示法:

#include<cstdio>#include<cstring>#include<string>#include<set>#include<iostream>#include<stack>#include<queue>#include<vector>#include<algorithm>#define mem(a,b) memset(a,b,sizeof(a))#define inf 0x3f3f3f3f#define mod 10000007#define debug() puts("what the fuck!!!")#define ll longlongusing namespace std;const int N=1000000+20;int nxt[N];string s;void get_next(string s){    int len=s.length();    int j=0,k=-1;    nxt[0]=-1;    while(j<len)        if(k==-1||s[j]==s[k])            nxt[++j]=++k;        else            k=nxt[k];}int min_max_express(string s,bool flag)//参数为true时求最小表示法,为false为最大表示法{    int i=0,j=1,k=0;    int len=s.length();    while(i<len&&j<len&&k<len)    {        int t=s[(j+k)%len]-s[(i+k)%len];        //二者相等,后移        if(t==0) k++;        else        {            if(flag)            {                if(t>0) j+=k+1;                else i+=k+1;            }            else            {                if(t>0) i+=k+1;                else j+=k+1;            }            if(i==j) j++;            k=0;        }    }    return min(i,j);}int main(){    std::ios::sync_with_stdio(false);    std::cin.tie(0);    while(cin>>s)    {        int len=s.length();        get_next(s);        int ans=len-nxt[len],cnt=1;        if(len%ans==0)            cnt=len/ans;        cout<<min_max_express(s,true)+1<<" "<<cnt<<" "<<min_max_express(s,false)+1<<" "<<cnt<<endl;    }    return 0;}
原创粉丝点击