zoukankan      html  css  js  c++  java
  • 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);
    }
  • 相关阅读:
    Linux Mint---shutter截图软件
    Linux Mint---fcitx中文,日语输入法
    Linux Mint---安装docky
    Linux Mint---开启桌面三维特效
    Linux Mint---ATI显卡驱动安装篇
    Linux Mint---更新软件源
    Spring Cloud 微服务服务间调用session共享问题
    Jooq批量插入 batch
    idea安装SonarLint语法检测插件
    JVM到底是什么?
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/9599119.html
Copyright © 2011-2022 走看看