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

转载于:https://www.cnblogs.com/virtual-north-Illya/p/10045095.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值