/*
       记一串数字真难。 5435
       今天比赛又是hjcAK的一天。
       今天开题顺序是312,在搞T1之前搞了T3
       昨天某谷月赛真是毒瘤。
       但是讲评的同学不错,起码T4看懂了...
       构造最优状态然后DP的思路真妙
*/        

Problem A lcp

给出字符串S,m个询问,每个询问含有$l1,r1,l2,r2$求|S|子串$[l1,r1]$和$[l2,r2]$的LCP(最长公共前缀)

对于100%的数据$ 1 \leq |S|,m \leq 10^5 , l1 \leq r1 ,l2 \leq r2$

 考虑二分答案套字符串Hash,于是就不用KMP了(我不会KMP)

 再说一下Hash的思路吧hash[i]表示S前i个字符的前缀哈希值,设基底为E=$31$,模数mo=$10^9+9$

 令hash[0]=0;对于$i \geq 1  计算方法如下 :hash[i]=hash[i-1] \times E+Val(s[i]) $ Val(x)是一个映射把char类型的x映射成一个int类型

所以利用前缀和的思想,如果不计模造成的负数问题$ Hash(l,r)=hash[r]-hash[l-1] \times E^{r-l+1} $

如果考虑模数造成负数问题那么要多mo几次,即  Hash(l,r) = ( (hash[r] - (hash[l-1] * pow[r-l+1] % mo) ) % mo + mo) % mo

得函数Hash(l,r)表示串S的子串[l,r]的哈希值。

那么这样就可以$O(1)$判断两个子串是不是相等了。套个二分就过了。

复杂度$O(m log_2 n)$

# include <bits/stdc++.h>
# define int long long
# define hash HASH
# define pow Pow
using namespace std;
const int N=1e5+10;
const int mo=1e9+7;
const int E=51;
char s[N];
int n,m,hash[N],pow[N];
inline int read()
{
    int X=0,w=0; char c=0;
    while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
    while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
    return w?-X:X;
}
int val(char ch){return ch-'a';}
int Hash(int l,int r){
    return ((hash[r]-hash[l-1]*pow[r-l+1]%mo)%mo+mo)%mo;
}
bool check(int len,int l1,int l2){ 
    if ((int) Hash(l1,l1+len-1)==(int) Hash(l2,l2+len-1))  return 1; 
    else return 0; 
}
signed main()
{
    freopen("lcp.in","r",stdin);
    freopen("lcp.out","w",stdout);
    n=read();m=read();
    scanf("%s",s+1);
    pow[0]=1;
    for (int i=1;i<=n;i++) pow[i]=pow[i-1]*E%mo;
    for (int i=1;i<=n;i++)
     hash[i]=(hash[i-1]*E+val(s[i]))%mo;
    int l1,r1,l2,r2; 
    while (m--) {
        l1=read();r1=read();l2=read();r2=read();
        int l=0,r=min(r1-l1+1,r2-l2+1),ans=0;
        while (l<=r) {
            int mid=(l+r)>>1;
            if (check(mid,l1,l2)) ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%lld\n",ans);
    } 
    return 0;
}
lcp.cpp

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案