zoukankan      html  css  js  c++  java
  • poj 2774

    题意:给出两个字符串,求这两个子串中最长相同子串长度

    策略:

    首先,我们可以将这两个字符串首尾相接,这样我们就可以获得一个长字符串,然后我们对这个新串求出height数组,然后枚举所有height并且找出两个sa,查出这两个sa是否在两个串内,这样就可以了如果是的话就用height更新ans即可

    还有一个细节要注意(虽然没写也能A,但总归是个hack点啊)

    状况如下:

    如图所示,下面的红色和绿色是两个字符串,两个褐色位置是sa[i]和sa[i-1],而蓝色部分就是height值

    所以问题体现在上面了:如果两个前缀相同,但某一个前缀越过了分界线怎么办?

    所以我们在分界线上插入一个无关字符(如‘#’),这样的话height在求的时候是无论如何不会越过分界线的

    这样就可以了

    代码:

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    using namespace std;
    int sa[200010];
    char s[200010];
    int height[200010];
    int rank[200010];
    char t1[100005];
    int f1[200010];
    int f2[200010];
    int f3[200010];
    int has[200010];
    int l,m=127;
    void turnit()
    {
        memcpy(f3,f1,sizeof(f3));
        memcpy(f1,f2,sizeof(f1));
        memcpy(f2,f3,sizeof(f2));
    }
    void get_sa()
    {
        for(int i=1;i<=l;i++)
        {
            f1[i]=s[i];
            has[f1[i]]++;
        }
        for(int i=2;i<=m;i++)
        {
            has[i]+=has[i-1];
        }
        for(int i=l;i>=1;i--)
        {
            sa[has[f1[i]]--]=i;
        }
        for(int k=1;k<=l;k<<=1)
        {
            int tot=0;
            for(int i=l-k+1;i<=l;i++)
            {
                f2[++tot]=i;
            }
            for(int i=1;i<=l;i++)
            {
                if(sa[i]>k)
                {
                    f2[++tot]=sa[i]-k;
                }
            }
            for(int i=1;i<=m;i++)
            {
                has[i]=0;
            }
            for(int i=1;i<=l;i++)
            {
                has[f1[i]]++;
            }
            for(int i=2;i<=m;i++)
            {
                has[i]+=has[i-1];
            }
            for(int i=l;i>=1;i--)
            {
                sa[has[f1[f2[i]]]--]=f2[i];
                f2[i]=0;
            }
            turnit();
            f1[sa[1]]=1;
            tot=1;
            for(int i=2;i<=l;i++)
            {
                if(f2[sa[i]]==f2[sa[i-1]]&&f2[sa[i]+k]==f2[sa[i-1]+k])
                {
                    f1[sa[i]]=tot;
                }else
                {
                    f1[sa[i]]=++tot;
                }
            }
            if(tot==l)
            {
                break;
            }
            m=tot;
        }
        for(int i=1;i<=l;i++)
        {
            rank[sa[i]]=i;
        }
        int f=0;
        for(int i=1;i<=l;i++)
        {
            if(rank[i]==1)
            {
                continue;
            }
            if(f)
            {
                f--;
            }
            int j=sa[rank[i]-1];
            while(s[i+f]==s[j+f])
            {
                f++;
            }
            height[rank[i]]=f;
        }
    }
    int main()
    {
        scanf("%s",t1+1);
        int l1=strlen(t1+1);
        l+=l1;
        for(int i=1;i<=l1;i++)
        {
            s[i]=t1[i];
        }
        scanf("%s",t1+1);
        l++;
        s[l]='#';
        int l2=strlen(t1+1);
        l+=l2;
        for(int i=l-l2+1;i<=l;i++)
        {
            s[i]=t1[i-l1-1];
        }
        get_sa();
        int ans=0;
        for(int i=2;i<=l;i++)
        {
            int e1=sa[i];
            int e2=sa[i-1];
            if(e1>e2)
            {
                swap(e1,e2);
            }
            if(e1<=l1&&e2>l1)
            {
                ans=max(ans,height[i]);
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    2-sat问题,输出方案,几种方法(赵爽的论文染色解法+其完全改进版)浅析 / POJ3683
    hdu 4587 2013南京邀请赛B题/ / 求割点后连通分量数变形。
    最小费用最大流粗解 poj2516
    hdu3078 建层次树+在线LCA算法+排序
    hdu 3594 Cactus /uva 10510 仙人掌图判定
    有向图最小路径覆盖方法浅析、证明 //hdu 3861
    hdu 1827 有向图缩点看度数
    条件转化,2-sat BZOJ 1997
    2-sat基础题 BZOJ 1823
    2-sat 分类讨论 UVALIVE 3713
  • 原文地址:https://www.cnblogs.com/zhangleo/p/9724167.html
Copyright © 2011-2022 走看看