Power Strings P5019
Description
给定若干长度小于等于1000000000的字符串,询问每个字符串最多由多少个相同的子串重复连接而成(循环节),例如ababab,最多由3个ab连接而成
Input
若干行,每行一个字符串。最后一行是一个"."点号,作为输入的结尾
Output
对应输入的每行,计算最多有多少个相同子串连接而成
Hint
This problem has huge input, use scanf instead of cin to avoid Time Limit Exceed.
Solution
枚举从1到m的子串长度并且用cnt来记录出现的次数肯定要超时,因为是O(m^2)的时间复杂度,而m是百万级别的数据。既然出现了循环节,那么循环的次数,也就是出现的次数=m/循环节的长度,那么循环节就一定是m的因数,用ins数组来存放m的所有因数。然后setb和sethash,定义findhash为bool类型返回一个循环节是否跟S串匹配,如果匹配,那么就输出答案,如果没有就继续找。由于这个是单调的,子串长度越小那么答案就越大,所以从小到大找只要findhash返回true就输出m/ins[i]。
注意事项:
1、不用把数组清零了会把power清掉。。。
2、if语句下面只管一句所以不要忘了{}。。。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 1000005
#define inf 0x3f3f3f3f
#define ull unsigned long long
using namespace std;
char S[maxn];
ull power[maxn],sumb,ha[maxn];
int ins[maxn];
int m,cnt;
void setins(){
cnt=0;
m=strlen(S+1);
for(int k=1;k<=sqrt(m);k++){
if(k*(m/k)==m){
ins[++cnt]=k;
ins[++cnt]=m/k;
}
}
sort(ins+1,ins+1+cnt);
}
void setb(int b){
power[0]=1;
for(int i=1;i<=m;i++){
power[i]=power[i-1]*b;
}
}
void sethash(int b){
ha[0]=0;
for(int i=1;i<=m;i++){
ha[i]=ha[i-1]*b+S[i]-'A'+1;
}
}
bool findhash(int i){
int len=ins[i];
for(int j=1;j+len-1<=m;j+=len){
if(ha[len]!=ha[j+len-1]-ha[j-1]*power[len])return false;
}
return true;
}
int main(){
while(1){
scanf("%s",S+1);
if(S[1]=='.')break;
else{
setins();
setb(53);
sethash(53);
for(int i=1;i<=cnt;i++){
if(!findhash(i))continue;
else{
printf("%d\n",m/ins[i]);
break;
}
}
}
}
return 0;
}