zoukankan      html  css  js  c++  java
  • poj 2774 Long Long Message

    求两个字符串的最长公共子串,用后缀数组做一下  只要求Height数组即可,然后统计答案就行了。—— by VANE

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    const int MAXN = 200005;
    
    char ch[MAXN], All[MAXN];
    int SA[MAXN], rank[MAXN], Height[MAXN], tax[MAXN], tp[MAXN], a[MAXN], n, m,l1,l2; 
    char s1[MAXN],s2[MAXN];
    //rank[i] 第i个后缀的排名; SA[i] 排名为i的后缀位置; Height[i] 排名为i的后缀与排名为(i-1)的后缀的LCP
    //tax[i] 计数排序辅助数组; tp[i] rank的辅助数组(计数排序中的第二关键字),与SA意义一样。
    //a为原串
    void RSort() {
        //rank第一关键字,tp第二关键字。
        for (int i = 0; i <= m; i ++) tax[i] = 0;
        for (int i = 1; i <= n; i ++) tax[rank[tp[i]]] ++;
        for (int i = 1; i <= m; i ++) tax[i] += tax[i-1];
        for (int i = n; i >= 1; i --) SA[tax[rank[tp[i]]] --] = tp[i]; //确保满足第一关键字的同时,再满足第二关键字的要求
        //cout<<"rank ";for(int i=1;i<=n;++i) printf("%d ",rank[i]);cout<<endl;
        //cout<<"SA ";for(int i=1;i<=n;++i) printf("%d ",SA[i]);cout<<endl;
    } //计数排序,把新的二元组排序。
    
    int cmp(int *f, int x, int y, int w) { return f[x] == f[y] && f[x + w] == f[y + w]; } 
    //通过二元组两个下标的比较,确定两个子串是否相同
    
    void Suffix() {
        //SA
        for (int i = 1; i <= n; i ++) rank[i] = a[i], tp[i] = i;
        m = 127 ,RSort(); //一开始是以单个字符为单位,所以(m = 127)
    
        for (int w = 1, p = 1, i; p < n; w += w, m = p) { //把子串长度翻倍,更新rank
    
            //w 当前一个子串的长度; m 当前离散后的排名种类数
            //当前的tp(第二关键字)可直接由上一次的SA的得到
            for (p = 0, i = n - w + 1; i <= n; i ++) tp[++ p] = i; //长度越界,第二关键字为0
            for (i = 1; i <= n; i ++) if (SA[i] > w) tp[++ p] = SA[i] - w;
            //cout<<"tp ";for(i=1;i<=n;++i) printf("%d ",tp[i]);cout<<endl;
            //更新SA值,并用tp暂时存下上一轮的rank(用于cmp比较)
            RSort(), swap(rank, tp), rank[SA[1]] = p = 1;
    
            //用已经完成的SA来更新与它互逆的rank,并离散rank
            for (i = 2; i <= n; i ++) rank[SA[i]] = cmp(tp, SA[i], SA[i - 1], w) ? p : ++ p;
        }
        //离散:把相等的字符串的rank设为相同。
        //LCP
        int j, k = 0;
        for(int i = 1; i <= n; Height[rank[i ++]] = k) 
            for( k = k ? k - 1 : k, j = SA[rank[i] - 1]; a[i + k] == a[j + k]; ++ k);
        //这个知道原理后就比较好理解程序
    }
    
    void Init() {
        scanf("%s%s",s1+1,s2+1);
        l1=strlen(s1+1),l2=strlen(s2+1);
        n=l1+l2+1;
        for(int i=1;i<=l1;++i) a[i]=(int)s1[i];
        a[l1+1]='*';
        for(int i=l1+2;i<=n;++i) a[i]=(int)s2[i-l1-1];
    }
    
    int main() {
        Init();
        Suffix();
        int ans=0;
        for(int i=2;i<=n;++i)
        {
            if(SA[i]<=l1&&SA[i-1]>l1) ans=max(ans,Height[i]);
            if(SA[i]>l1&&SA[i-1]<=l1) ans=max(ans,Height[i]);
        }
        cout<<ans;
    }
  • 相关阅读:
    POJ 3253 Fence Repair
    POJ 2431 Expedition
    NYOJ 269 VF
    NYOJ 456 邮票分你一半
    划分数问题 DP
    HDU 1253 胜利大逃亡
    NYOJ 294 Bot Trust
    NYOJ 36 最长公共子序列
    HDU 1555 How many days?
    01背包 (大数据)
  • 原文地址:https://www.cnblogs.com/nbwzyzngyl/p/8195695.html
Copyright © 2011-2022 走看看