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
题意: 每组数据给出一个字符串,求它循环左移形成的各自符串中字典序最小的字符串及出现次数+字典序最大的字符串及出现次数。
分析: 求循环移动后的各自符串中字典序最小(大)的字符串有一个特定的算法,即最小(大)表示法,模板见博客:最小(大)表示法模板总结_Cloth的博客-CSDN博客,之后只需要计算出它们的出现次数就行了,模拟几组样例发现出现次数与最小循环节有关,如果字符串可以完全由最小循环节拼出,答案就为最小循环节的段数,如果不能拼出,答案就为1。
具体代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
char s[1000005];
int _next[1000005];
//最小表示法
int get_minstring(char *s)
{
int len = strlen(s);
int i = 0, j = 1, k = 0;
while(i<len && j<len && k<len)
{
int t = s[(i+k)%len]-s[(j+k)%len];
if(t == 0)
k++;
else
{
if(t > 0)
i += k+1;
else
j += k+1;
if(i == j)
j++;
k = 0;
}
}
return min(i, j);
}
//最大表示法
int get_maxstring(char *s)
{
int len = strlen(s);
int i = 0, j = 1, k = 0;
while(i<len && j<len && k<len)
{
int t = s[(i+k)%len]-s[(j+k)%len];
if(t == 0)
k++;
else
{
if(t > 0)
j += k+1;
else
i += k+1;
if(i == j)
j++;
k = 0;
}
}
return min(i, j);
}
signed main()
{
while(~scanf("%s", s+1))
{
int len = strlen(s+1);
for(int i = 2, j = 0; i <= len; i++)
{
while(j && s[j+1] != s[i])
j = _next[j];
if(s[j+1] == s[i])
j++;
_next[i] = j;
}
int times = 1;
if(len % (len-_next[len]) == 0)
times = len / (len-_next[len]);
printf("%d %d %d %d\n", get_minstring(s+1)+1, times, get_maxstring(s+1)+1, times);
}
return 0;
}