Luogu P3546 [POI2012]PRE-Prefixuffix 神奇的递推+哈希

设$f[i]$表示切掉前$i$位和后$i$位后,即剩下$s[i+1]到s[n-i]$,的公共前后缀长度。此时我们发现,$f[i-1]$相对于$f[i]$少切了两个$char$,所以有$f[i-1]\leq f[i]+2$,所以我们可以有上界地递推了。

当然最终答案是$max(f[i]+i),且1-s[i]与s[n-i+1]-s[n]$是匹配的。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define R register int
using namespace std;
namespace Fread {
    static char B[1<<15],*S=B,*D=B;
    #define getchar() (S==D&&(D=(S=B)+fread(B,1,1<<15,stdin),S==D)?EOF:*S++)
    inline int g() {
        R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
        do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
    } inline bool isempty(const char& ch) {return ch<=36||ch>=127;}
    inline void gs(char* s) {register char ch; while(isempty(ch=getchar())); do *s++=ch; while(!isempty(ch=getchar()));}
}using Fread::g; using Fread::gs;
const int M=1E9+7,N=1000010,B=131;
ll h[N],p[N]; int n,f[N],ans; char s[N];
inline ll hsh(int l,int r) {return (h[r]+M-h[l-1]*p[r-l+1]%M)%M;}
signed main() {
#ifdef JACK
    freopen("NOIPAK++.in","r",stdin);
#endif
    n=g(); gs(s+1); p[0]=1; 
    for(R i=1;i<=n;++i) p[i]=p[i-1]*B%M;
    for(R i=1;i<=n;++i) h[i]=(h[i-1]*B+s[i])%M;
    for(R i=(n>>1);i;--i) {
        R now=f[i+1]+2; while(now+i>(n>>1)) --now;
        while(now&&!(hsh(i+1,i+now)==hsh(n-i-now+1,n-i))) --now; f[i]=now;
    } for(R i=1;i<=(n>>1);++i) if(hsh(1,i)==hsh(n-i+1,n)) ans=max(ans,i+f[i]);
    printf("%d\n",ans);
}    
 

2019.06.13

猜你喜欢

转载自www.cnblogs.com/Jackpei/p/11013675.html