UVA10298 Power Strings

UVA10298 Power Strings

hash+乘法逆元+一点点数学知识

我们用取余法算出主串的hash,然后从小到大枚举子串的长度

显然,如果若干个子串的复制的hash值之和等于主串的hash值,那么答案就得到了。

然后我们计算子串(设子串长度为 i )的hash值:

hash=t*(1+base^i+base^2i+...+base^(len-i))

如果直接暴力求,那么显然会TLE

于是我们进行推导:

设:
Si=1+base^i+base^2i+...+base^(len-i)
S=Si*(base^i)=base^i+base^2i+base^3i+...+base^len
所以
S-Si=base^len-1=Si*(base^i-1)
Si=(base^len-1)/(base^i-1)

我们利用快速幂可以很快地得出结果

但是涉及到取模除法运算,所以我们可以用乘法逆元,这里不详细讲了

根据费马小定理,base^i-1关于mod的乘法逆元为 (base^i-1)^(mod-2)

end.


然鹅更常用的判断循环子串方法在这里:point_here(本题升级版)


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef unsigned long long ull; 
const int mod=1e9+7;
const int base=131;
char c[2000004];
inline ull ksm(int x,int y){ //快速幂
    ull ans=1;
    for(;y;y>>=1){
        if(y&1) ans=ans*(ull)x%mod;
        x=1LL*x*x%mod;
    }
    return ans%mod;
}
int main(){
    do{
        scanf("%s",c);
        if(c[0]=='.') return 0;
        int ans=1,len=strlen(c);
        ull tot=0,t=0;
        for(int i=0;i<len;++i) tot=(tot*base+(ull)c[i])%mod; //计算主串hash值
        for(int i=1;i<=len/2;++i){
            t=(t*base+(ull)c[i-1])%mod; //子串hash值
            if(len%i) continue; //子串长度不被整除不可能有解
            ull tmp=ksm(base,i)-1;
            ull s=(ksm(base,len)-1)*ksm(tmp,mod-2)%mod;
            if(t*s%mod==tot){ //刚好可以填充
                ans=len/i; break;
            }
        }
        printf("%d
",ans);
    }while(1);
}
原文地址:https://www.cnblogs.com/kafuuchino/p/9599119.html