[最小循环节][最小(大)表示法]String Problem HDU3374

该博客主要讨论如何计算一个给定字符串通过循环左移形成的字典序最小和最大的字符串及其出现次数。博主介绍了最小表示法和最大表示法的算法,并提供了一个C++实现的示例代码,用于找到这些字符串并计算它们的出现频率。文章强调了解决这类问题的关键在于理解字符串的最小循环节,并以此来确定字符串在所有循环移位中的分布情况。
摘要由CSDN通过智能技术生成

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值