字符串乘方(POJ NO.1408)
总时间限制: 3000ms
内存限制: 65536kB
Question
描述
给定两个字符串a和b,我们定义a*b为他们的连接。例如,如果a=”abc” 而b=”def”, 则a*b=”abcdef”。 如果我们将连接考虑成乘法,一个非负整数的乘方将用一种通常的方式定义:a^0=””(空字符串),a^(n+1)=a*(a^n)。输入
每一个测试样例是一行可打印的字符作为输入,用s表示。s的长度至少为1,且不会超过一百万。最后的测试样例后面将是一个点号作为一行。输出
对于每一个s,你应该打印最大的n,使得存在一个a,让s=a^n
样例输入
abcd
aaaa
ababab
.
样例输出
1
4
3
提示
本问题输入量很大,请用scanf代替cin,从而避免超时。
来源
Waterloo local 2002.07.01
My Hints
Algorithm
看到题目的提示说用scanf代替cin,于是我一开始查阅Artificial Intelligence的博客后,选择了sscanf(str, “%[^.]”, string) ;
输出依旧使用cout,调试时发现无法输出,只能改为printf才能够输出。但当我输入样例时发生错误,捣鼓了半天,不得已之下做了“[小林丸号]1(Kobayashi Maru)式处理”:
将输入改为cin >> str && str != "."
,为减少超时可能,我们先关闭流同步:std::ios_base::sync_with_stdio(false);
(当然也可以将str定义为char类型的字符数组,利用scanf输入比定义为string类型的输入会更通用一些scanf("%s",c)&&c[0]!='.'
)从而加快cin的输入速度。此时输入正常。可进行KMP算法的编写。
KMP算法在姚光超的专栏讲解得十分清楚,推荐大家去看,这里不再赘述。
由于我们规定fail数组下标从1开始,故将str前加空格与Fail数组一致。利用KMP算法更新fail数组之后,用 数组总长(len)−当前循环节(fail[len]) 即可得到最小循环节。若总长不能整除最小循环节长度,则无循环节,即循环节为其本身;否则循环节为总长除以最小循环节长度。
Codes
代码主要思想参考getsum的博客。
@ hzhang_97@foxmail.com
// Author: Florence
// Created Time: 2017-08-18 09:37:30
#include <iostream>
#include <cstring>
#define max_n 1000010
using namespace std;
string str;
int fail[max_n];
int i,j,len,loop;
int main(int argc, char** argv) {
std::ios_base::sync_with_stdio(false);//关闭流同步,从而加快cin的输入速度
while (cin >> str && str != "."){
memset(fail,0,sizeof(fail));//每组数据均应初始化
len = str.length();
str = " " + str;//由于我们规定Fail数组下标从1开始,故将str前加空格与fail数组一致
j = 0;
//利用KMP算法更新fail数组
for (i = 2;i <= len;i++){
while (j > 0 && str[j+1] != str[i]) j = fail[j];
if (str[j+1] == str[i]) j++;
fail[i] = j;
}
loop = len - fail[len];//得到最小循环节
//若总长不能整除最小循环节长度,则无循环节,即循环节为其本身
if (len % loop) printf("%d\n",1);
//否则循环节为总长除以最小循环节长度
else printf("%d\n",len / loop);
}
return 0;
}
此题考查KMP算法的应用,值得一写。
- 星舰学院中著名的“小林丸”测试:学员模拟指挥的星舰,接到位于中立地带“小林丸”号运输舰发出的求救信号,而后,根据星际舰队(starfleet)的规定,星舰必须前往营救。在营救行动即将开始的时候,会有三艘克林贡战船解除隐形,进而无理由的攻击星舰。该测试是一个不可能完成的任务。它测试的目的是:通过不可能完成的任务,锻炼学员承受压力的能力,并能够使其坦然面对最后的时刻。当电影临近结束时,我们发现柯克船长更改了模拟训练装置,使它实际上可以获胜。柯克非常聪明,但他并没有解决小林丸号的困境,只是避开了它而已。 ↩