传送门
String Problem
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4445 Accepted Submission(s): 1814
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
题目描述:
给你一个字符串,让你求出其的最小表示的首个位置以及最大表示的首个位置以及最小最大表示分别出现了多少次。
题目分析:
这是一个很棒的综合性字符串模板的问题。其中包括了最小表示法、最大表示法的求法以及KMP的运用。
其中最小表示为n个循环同构字符串中,字典序最小的一个(最大表示为字典序最大的一个)。
对于最小最大表示,我们可以通过双指针在O(n)的时间内求出。
对于第二个要求,题目要求我们求出最小最大表示出现的次数,不难发现,他们出现的次数跟等于循环节的个数,我们可以通过KMP的next数组进行求解。时间复杂度同样是O(n)。
代码:
#include <bits/stdc++.h>
#define maxn 2000005
using namespace std;
char str[maxn];
int nextt[maxn];
void get_next(char *a,int len){//求解next数组板子
int i=0,j=nextt[0]=-1;
while(i<len){
while(j!=-1&&a[i]!=a[j]) j=nextt[j];
nextt[++i]=++j;
}
}
int get_minn(char *a,int len){//最小表示法板子
int i=0,j=1;
for(int i=0;i<len;i++){
str[i+len]=str[i];
}
while(i<len&&j<len){
int k;
for(k=0;k<len&&a[k+i]==a[k+j];k++);
if(k==len) break;
if(a[k+i]>a[k+j]){
i=i+k+1;
if(i==j) i++;
}
else{
j=j+k+1;
if(i==j) j++;
}
}
return min(i,j);
}
int get_maxx(char *a,int len){//最大表示法板子
int i=0,j=1;
for(int i=0;i<len;i++){
str[i+len]=str[i];
}
while(i<len&&j<len){
int k;
for(k=0;k<len&&a[k+i]==a[k+j];k++);
if(k==len) break;
if(a[k+i]<a[k+j]){
i=i+k+1;
if(i==j) i++;
}
else{
j=j+k+1;
if(i==j) j++;
}
}
return min(i,j);
}
int main()
{
while(~scanf("%s",str)){
int len=strlen(str);
memset(nextt,0,sizeof(nextt));
get_next(str,len);
int minn=get_minn(str,len);
int maxx=get_maxx(str,len);
int tmp=nextt[len];
if(len%(len-tmp)!=0){
cout<<minn+1<<" 1 "<<maxx+1<<" 1"<<endl;
}
else{
cout<<minn+1<<" "<<len/(len-tmp)<<" "<<maxx+1<<" "<<len/(len-tmp)<<endl;
}
}
}