• BZOJ 3230 相似子串 ——后缀数组


    题目的Source好有趣。

    我们求出SA,然后求出每一个后缀中与前面本质不同的字符串的个数。

    然后二分求出当前的字符串。

    然后就是正反两次后缀数组求LCP的裸题了。

    要注意,这时两个串的起点可能会相同,所以需要判掉。

    无论读入还是输出都有可能爆long long,要注意

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define F(i,j,k) for (int i=j;i<=k;++i)
    #define D(i,j,k) for (int i=j;i>=k;--i)
    #define maxn 200500
    #define inf 0x3f3f3f3f
    #define ll long long
     
    int _log2[maxn];
     
    struct Suffix_Array{
        int s[maxn],cnt[maxn],tmp[maxn],sa[maxn],h[maxn],rk[maxn];
        int st[maxn][21];
        ll pre[maxn],Sum;
        void build(int n,int m)
        {
            n++; int i,j,k;
            F(i,0,2*n+5) sa[i]=tmp[i]=h[i]=rk[i]=0;
            F(i,0,m-1) cnt[i]=0;
            F(i,0,n-1) cnt[rk[i]=s[i]]++;
            F(i,1,m-1) cnt[i]+=cnt[i-1];
            F(i,0,n-1) sa[--cnt[rk[i]]]=i;
            for (k=1;k<=n;k<<=1)
            {
                F(i,0,n-1) {j=sa[i]-k;if(j<0)j+=n;tmp[cnt[rk[j]]++]=j;}
                sa[tmp[cnt[0]=0]]=j=0;
                F(i,1,n-1)
                {
                    if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i;
                    sa[tmp[i]]=j;
                }
                memcpy(rk,sa,n*sizeof(int));memcpy(sa,tmp,n*sizeof(int));
                if (j>=n-1) break;
            }
            for (i=k=0;i<n;h[rk[i++]]=k)
                for (k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
            F(i,0,n-1) st[i][0]=h[i];
            F(i,1,20) F(j,0,n-(1<<i)) st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
            F(i,1,n-1) pre[i]=pre[i-1]+n-sa[i]-h[i]-1;
            Sum=pre[n-1];
        }
        int query(int l,int r)
        {
            int t=_log2[r-l+1];
            return min(st[l][t],st[r-(1<<t)+1][t]);
        }
        ll lcp(int a,int b)
        {
            if (a==b) return inf;
            int aa=rk[a],bb=rk[b];
            return query(min(aa,bb)+1,max(aa,bb));
        }
        void find(ll x,int n,int &l,int &r)
        {
            int le=1,ri=n;
            while (le<ri)
            {
                int mid=le+ri>>1;
                if (pre[mid]>=x) ri=mid;
                else le=mid+1;
            }
            int tmp=x-pre[le-1]+h[le];
            l=sa[le];r=l+tmp-1;
        }
    }SA,SB;
     
    int n,q;
    char s[maxn];
     
    int main()
    {
        F(i,2,maxn-1) _log2[i]=_log2[i>>1]+1;
        scanf("%d%d",&n,&q);
        scanf("%s",s);
        F(i,0,n-1)
        {
            SA.s[i]=s[i]-'a'+1;
            SB.s[n-i-1]=s[i]-'a'+1;
        }
        SA.s[n]=0; SB.s[n]=0;
        SA.build(n,30); SB.build(n,30);
        F(i,1,q)
        {
            ll x,y;
            int xl,xr,yl,yr;
            scanf("%lld%lld",&x,&y);
            if (x>SA.Sum||y>SA.Sum) {printf("-1
    ");continue;}
            SA.find(x,n,xl,xr); SA.find(y,n,yl,yr);
            ll lcp=SA.lcp(xl,yl),rcp=SB.lcp(n-yr-1,n-xr-1);
            int l=min(xr-xl+1,yr-yl+1); lcp=min(lcp,(ll)l); rcp=min(rcp,(ll)l);
            printf("%lld
    ",lcp*lcp+rcp*rcp);
        }
    }
    

      

  • 相关阅读:
    单点登录的实现原理
    Entity Framework添加记录时获取自增ID值
    linq to entity查询,日期格式化
    Linq之GroupBy用法
    IIS HTTPS CA
    CallContext和多线程
    windows平台 culture name 详细列表
    如何在WCF中集成unity
    .NET MVC 依赖注入 来龙去脉
    apache虚拟主机安装注意事项
  • 原文地址:https://www.cnblogs.com/SfailSth/p/6646821.html
Copyright © 2020-2023  润新知