POJ

题意:给定若干个长度小于等于\(1e6\)的小写字母字符串,询问每个字符串最多由多少个相同的子串重复连接而成.

分析:字符串哈希记录字符串每一段的值.然后从小到大枚举\(n\)(设\(n\)为字符串的长度)的约数,判断每一段约数长度的哈希值是否相等即可.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define ull unsigned long long
using namespace std;
const int N=1000005;
char s[N];int p=1e9+7;
ull Base[N],sum[N];
int main(){
    Base[0]=1;for(int i=1;i<N;++i)Base[i]=Base[i-1]*p;
    while(1){
        scanf("%s",s+1);if(s[1]=='.')break;
        int n=strlen(s+1);sum[0]=0;
        for(int i=1;i<=n;++i)
            sum[i]=sum[i-1]*p+(ull)s[i]-'a'+1;//懒得写双哈希了
        for(int i=1;i<=n;++i){//枚举约数
            if(n%i)continue;//不是约数就直接跳过
            ull s=sum[i]-sum[0];//先算出第一段
            int bj=1;
            for(int j=i;j+i<=n;j+=i){
                if(sum[j+i]-sum[j]*Base[i]!=s){//如果这个不满足就跳出,节约时间
                    bj=0;break;
                }
            }
            if(bj){//如果当前约数满足,直接输出,保证最大
                printf("%d\n",n/i);
                break;
            }
        }
    }
    return 0;
}
01-14 05:19