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;
}
posted @ 2018-11-30 16:46  虚拟北方virtual_north。  阅读(190)  评论(0编辑  收藏  举报