bzoj2803: [Poi2012]Prefixuffix(hash+性质推导)

题意:
给出一个长度为n的串S,求满足下面条件的最大的L:

  1. L<=n/2
  2. S的L前缀和S的L后缀是循环同构的。

思路:
设前缀为 a a a,后缀为 b b b,如果 a , b a,b a,b循环同构,那么 a , b a,b a,b是由一个字符串加上两个 b o r d e r border border形成的。
即如下图所示:
在这里插入图片描述
s 1 , i = s l + 1 , n , s i + 1 , j = s k , l s_{1,i}=s_{l+1,n},s_{i+1,j}=s_{k,l} s1,i=sl+1,n,si+1,j=sk,l
于是考虑枚举可行的 i i i,并对于每个 i i i求出满足条件的最大的 j j j
我们设 f i = j f_i=j fi=j
那么可以得出一个结论: f i ≤ f i + 1 + 2 f_i\le f_{i+1}+2 fifi+1+2 (证明显然)
然后就暴力枚举 j j j即可,摊下来复杂度 O ( n ) O(n) O(n)
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int N=1e6+5;
char s[N];
int n,f[N];
typedef unsigned long long Ull;
typedef long long ll;
const Ull bas=141;
const int mod=1e9+9;
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
struct string_hash{
    Ull pw[N],ss[N];
    int pww[N],sss[N];
    inline void init(){
        pw[0]=pww[0]=1;
        for(ri i=1;i<=n;++i)pw[i]=pw[i-1]*bas,pww[i]=mul(pww[i-1],bas);
        for(ri i=1;i<=n;++i)ss[i]=ss[i-1]*bas+(s[i]-'0'+15),sss[i]=add(mul(sss[i-1],bas),s[i]-'0'+15);
    }
    inline Ull gethash1(int l,int r){return ss[r]-ss[l-1]*pw[r-l+1];}
    inline int gethash2(int l,int r){return dec(sss[r],mul(sss[l-1],pww[r-l+1]));}
    inline bool check(int l1,int r1,int l2,int r2){return gethash1(l1,r1)==gethash1(l2,r2)&&gethash2(l1,r1)==gethash2(l2,r2);}
}S;
int main(){
    scanf("%d%s",&n,s+1);
    S.init();
    f[n>>1]=0;
    int ans=0;
    for(ri l1,r1,l2,r2,i=(n>>1)-1;~i;--i){
        l1=i+1,r2=n-i;
        for(r1=min(n>>1,i+1+f[i+1]+1),l2=n+1-r1;r1>=l1;--r1,++l2)if(S.check(l1,r1,l2,r2))break;
        f[i]=r1-l1+1;
        if(S.check(1,i,n-i+1,n))ans=max(ans,i+f[i]);
    }
    cout<<ans;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值