zoukankan      html  css  js  c++  java
  • poj1743

    题解:

    二分枚举子串长度,判断解是否成立

    把互相之间LCP大于等于长度的分为一组

    这通过个扫一遍height即可

    因为后缀是有序的

    相邻的后缀间的LCP必定的极大的

    接下来就找到每个组里后缀sa值最大和最小的

    如果差值大于(等于)k就成立

    因为这样小下标的后缀沿着LCP下去走k步才不会盖到大下标的后缀。

    代码:

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    const int N=20005;
    using namespace std;
    int n,p,q,k,a[N],v[N],h[N],sa[2][N],rk[2][N];
    void calsa(int sa[N],int rk[N],int SA[N],int RK[N])
    {
        for (int i=1;i<=n;i++)v[rk[sa[i]]]=i;
        for (int i=n;i;i--)
         if (sa[i]>k)SA[v[rk[sa[i]-k]]--]=sa[i]-k;
        for (int i=n-k+1;i<=n;i++)SA[v[rk[i]]--]=i;
        for (int i=1;i<=n;i++)
         RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i-1]]!=rk[SA[i]]||rk[SA[i]+k]!=rk[SA[i-1]+k]);
    }
    void getsa()
    {
        memset(v,0,sizeof(v));
        p=0,q=1;
        for (int i=1;i<=n;i++)v[a[i]]++;
        for (int i=1;i<=200;i++)v[i]+=v[i-1];
        for (int i=1;i<=n;i++)sa[p][v[a[i]]--]=i;
        for (int i=1;i<=n;i++)
         rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i-1]]!=a[sa[p][i]]);
        for (k=1;k<n;k<<=1,swap(p,q))calsa(sa[p],rk[p],sa[q],rk[q]);
    }
    void geth()
    {
        k=0;
        for (int i=1;i<=n;i++)
         if (rk[p][i]==1)h[rk[p][i]]=0;
         else 
          {
            int j=sa[p][rk[p][i]-1];
            while (a[i+k]==a[j+k])k++;
            h[rk[p][i]]=k;
            if (k>0)k--;
          }
    }
    int jud(int x)
    {
        int mn=sa[p][1],mx=sa[p][1];
        for (int i=2;i<=n;i++)
         if (h[i]<x)mn=mx=sa[p][i];
         else 
          {
            mn=min(mn,sa[p][i]);
            mx=max(mx,sa[p][i]);
            if (mx-mn>=x)return 1;
          }
        return 0;
    }
    void solve()
    {
        int l=0,r=n/2,ans;
        while (l<=r)
         {
            int mid=(l+r)>>1;
            if (jud(mid))ans=mid,l=mid+1;
            else r=mid-1;
         }
        if (ans<4)puts("0");
        else printf("%d
    ",ans+1);
    }
    int main()
    {
        while (~scanf("%d",&n),n)
         {
            for (int i=1;i<=n;i++)scanf("%d",&a[i]);
            n--;
            for (int i=1;i<=n;i++)a[i]=a[i+1]-a[i]+100;
            getsa();
            geth();
            solve();
         }
        return 0;
    }
  • 相关阅读:
    07 MySQL之视图
    05 MySQL之查询、插入、更新与删除
    04 MySQL之函数
    02 MySQL之数据表的基本操作
    03 MySQL之数据类型和运算符
    Django之通用视图
    01 MySQL之数据库基本操作
    Elasticsearch-Head基本使用方法
    PinPoint使用手册(转)
    rest-assured学习资料
  • 原文地址:https://www.cnblogs.com/xuanyiming/p/8490349.html
Copyright © 2011-2022 走看看