• POJ 1743 不可重叠的最长重复子串


    原问题,其实是找最长的相似子串,所谓相似就是一个子串每个值加上一个偏移值可以得到另一个子串。

    我们先求原数组的差值数组,对新数组求后缀数组,二分答案,判定是否有某个Height数组中的sa最小值与最大值之差大于当前枚举的子串长度。

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <string>
    #include <string.h>
    #include <stdio.h>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <cmath>
    #include <ctime>
    #include <cassert>
    #include <sstream>
    using namespace std;
    
    const int N=2e6+10010;
    
    int sa[N];
    int t1[N],t2[N],c[N];
    int rk[N],height[N];
    
    inline int cmp(int *r,int a,int b,int l){
        return r[a]==r[b]&&r[a+l]==r[b+l];
    }
    int s[N];
    void calcSA (int *s,int n,int m) {
        int i,j,p,*x=t1,*y=t2;
        for(i=0;i<m;i++)c[i]=0;
        for(i=0;i<n;i++)c[x[i]=s[i]]++;
        for(i=1;i<m;i++)c[i]+=c[i-1];
        for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
        for(j=1;j<=n;j<<=1){
            p=0;
            for(i=n-j;i<n;i++)y[p++]=i;
            for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; // 排名从小到大,如果pos比j大,则suffix(sa[i]-j)的第二关键字为p
            for(i=0;i<m;i++)c[i]=0;
            for(i=0;i<n;i++)c[x[y[i]]]++;
            for(i=1;i<m;i++)c[i]+=c[i-1];
            for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; // 根据第二关键字从大到小,确定新一轮sa
            swap(x,y);
            p=1;x[sa[0]]=0;
            for(i=1;i<n;i++)
                x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
            if(p>=n)break;
            m=p;
        }
    }
    
    void calcHeight(int *s,int n) {
        int i,j,k=0;
        for(i=0;i<=n;i++)rk[sa[i]]=i;
        for(i=0;i<n;i++){
            if(k)k--; // h[i]>=h[i-1]-1
            j=sa[rk[i]-1]; // suffix(j)排名在suffix(i)前一位
            while(s[i+k]==s[j+k])k++; // 暴力计算lcp
            height[rk[i]]=k;
        }
    }
    
    bool ok(int n,int m) {
        int mi=sa[1],mx=sa[1];
        for (int i=2;i<=n;i++) {
            if (height[i]<m) {
                mi=sa[i];
                mx=sa[i];
                continue;
            }
            mi=min(mi,sa[i]);
            mx=max(mx,sa[i]);
            if (mx-mi>m) return true;
        }
        return false;
    }
    
    int a[N];
    int main () {
        int n;
        while (scanf("%d",&n)!=EOF,n) {
            for (int i=0;i<n;i++)
                scanf("%d",a+i);
            --n;
            for (int i=0;i<n;i++) {
                s[i]=a[i+1]-a[i]+100; // 保证正数
            }
            s[n]=0;
            calcSA(s,n+1,200);
            calcHeight(s,n);
            int l=4,r=n/2,ret=-1;
            while (l<=r) {
                int m=(l+r)>>1;
                if (ok(n,m)) {
                    ret=m;
                    l=m+1;
                }
                else
                    r=m-1;
            }
            printf("%d
    ",ret+1);
        }
        return 0;
    }
  • 相关阅读:
    C#中使用MATLAB
    各种插值法及效果图对比
    Visual Studio中你所不知道的智能感知
    C#中使用Surfer
    XCode中连接使用GitHub
    个人作业Week1
    个人作业Week3
    个人作业Week2
    第一次作业——subway
    执行ajax加载页面中的js总结
  • 原文地址:https://www.cnblogs.com/micrari/p/4820444.html
Copyright © 2020-2023  润新知