• 【CodeForces】961 F. k-substrings 字符串哈希+二分


    【题目】F. k-substrings

    【题意】给定长度为n的串S,对于S的每个k-子串$s_ks_{k+1}...s_{n-k+1},kin[1,left lceil frac{n}{2} ight ceil]$,找到满足[奇数长度][严格子串][同时是前缀和后缀]的最长子串。n<=10^6。

    【算法】字符串哈希+二分

    【题解】任意两个对应子串,它们有一个不变量——它们的中心一定是i和n-i+1。而且固定中心之后,能延伸的最长相等子串是可以二分+哈希得到的。

    所以枚举k,二分+哈希处理出以k为中心和对应串相等的最长子串半长L。

    然后实际上是一个递减序列覆盖求单点最值的问题,有一个巧妙的解决方法,在k-L+1处标记答案,然后从前往后扫描每次和ans[i]=max{ans[i],ans[i-1]-2}。因为这是一个从大到小的递减序列,所以就不需要考虑终止,因为<0就自然没有意义了。

    复杂度O(n log n)。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=1000010;
    int ans[maxn],n;
    char s[maxn];
    int a[maxn],b[maxn],c[maxn],d[maxn];
    const int MOD1=993258975,MOD2=934384734,base1=233,base2=197;
    bool check(int l,int r,int L,int R){
        int x=r-l+1;//
        int ans1=(a[r]-1ll*a[l-1]*c[x]%MOD1+MOD1)%MOD1;
        int ans2=(a[R]-1ll*a[L-1]*c[x]%MOD1+MOD1)%MOD1;
        if(ans1!=ans2)return 0;
        ans1=(b[r]-1ll*b[l-1]*d[x]%MOD2+MOD2)%MOD2;
        ans2=(b[R]-1ll*b[L-1]*d[x]%MOD2+MOD2)%MOD2;
        if(ans1!=ans2)return 0;
        return 1;
    }
    int main(){
        scanf("%d%s",&n,s+1);c[0]=d[0]=1;
        for(int i=1;i<=n;i++)a[i]=(1ll*a[i-1]*base1+s[i])%MOD1,b[i]=(1ll*b[i-1]*base2+s[i])%MOD2;
        for(int i=1;i<=n;i++)c[i]=1ll*c[i-1]*base1%MOD1,d[i]=1ll*d[i-1]*base2%MOD2;
        memset(ans,-1,sizeof(ans));
        for(int i=1;i<=n/2;i++){
            int l=1,r=i+1,mid;
            while(l<r){
                mid=(l+r)>>1;
                if(check(i-mid+1,i+mid-1,n-i+1-mid+1,n-i+1+mid-1))l=mid+1;else r=mid;
            }
            l--;
            ans[i-l+1]=max(ans[i-l+1],2*l-1);
        }
        for(int i=1;i<=n/2;i++){
            ans[i]=max(ans[i],ans[i-1]-2);
            printf("%d ",ans[i]);
        }
        if(n&1)printf("-1");
        return 0;
    }
    View Code

    字符串哈希:将字符串换算成base进制的数字取模接近int的素模数,比较两段字符串时判断a[r]-a[l-1]*base^(r-l+1)是否相等即可。当然需要双哈希。

    如果是建哈希表,就建一条链存真实值。(参考插头DP)

    顺便提一下朴素KMP处理一次询问的方法:整个字符串跑出fail数组,那么从n一直fail到最小的>0的位置就是最小首尾匹配串了。KMP的fail树十分强大。

  • 相关阅读:
    无限级分类Asp.net Mvc实现
    Asp.net MVC 简单分页 自做简单分页
    asp.net mvc的权限管理设计
    PHP的流程控制结构
    PHP的变量
    测试笔试题之测试用例设计题
    测试笔试题之相关概念
    HTML5的全新语义化元素
    软件测试的基础之测试生成
    HTML5表单
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8823892.html
Copyright © 2020-2023  润新知