后缀数组 POJ 2217 Secretary

题目链接

题意:求两个字符串的最长公共子串

分析:做法是构造新的串是两个串连接而成,中间用没有出现的字符隔开(因为这样才能保证S的后缀的公共前缀不会跨出一个原有串的范围),即newS = S + ‘$‘ + T。对其求sa数组和height数组,取最小值的height[i],且两个后缀串属于不同的字符串。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>

typedef long long ll;
const int N = 1e4 + 5;
std::string t, str;
int sa[N<<1], rank[N<<1];
int height[N<<1];
int tmp[N<<1];

int n, k;
bool cmp_sa(int i, int j) {
    if (rank[i] != rank[j]) {
        return rank[i] < rank[j];
    } else {
        int ri = i + k <= n ? rank[i+k] : -1;
        int rj = j + k <= n ? rank[j+k] : -1;
        return ri < rj;
    }
}

void get_sa(std::string S, int *sa) {
    n = S.length ();
    for (int i=0; i<=n; ++i) {
        sa[i] = i;
        rank[i] = i < n ? (int) S[i] : -1;
    }
    for (k=1; k<=n; k<<=1) {
        std::sort (sa, sa+n+1, cmp_sa);
        tmp[sa[0]] = 0;
        for (int i=1; i<=n; ++i) {
            tmp[sa[i]] = tmp[sa[i-1]] + (cmp_sa (sa[i-1], sa[i]) ? 1 : 0);
        }
        for (int i=0; i<=n; ++i) {
            rank[i] = tmp[i];
        }
    }
}

void get_height(std::string S, int *sa, int *height) {
    int n = S.length ();
    for (int i=0; i<n; ++i) {
        rank[sa[i]] = i;
    }
    int h = 0;
    height[0] = 0;
    for (int i=0; i<n; ++i) {
        int j = sa[rank[i]-1];
        if (h > 0) {
            h--;
        }
        for (; j+h<n && i+h<n; h++) {
            if (S[j+h] != S[i+h]) {
                break;
            }
        }
        height[rank[i]-1] = h;
    }
}

int run(int len1, std::string S) {
    get_sa (S, sa);
    get_height (S, sa, height);
    int ret = 0;
    for (int i=0; i<S.length (); ++i) {
        if ((sa[i]<len1) != (sa[i+1]<len1)) {
            ret = std::max (ret, height[i]);
        }
    }
    return ret;
}

int main() {
    int T; scanf ("%d", &T);
    getchar ();
    while (T--) {
        getline (std::cin, t);
        str = t;
        int len1 = t.length ();
        getline (std::cin, t);
        str += ‘$‘ + t;
        int ans = run (len1, str);
        printf ("Nejdelsi spolecny retezec ma delku %d.\n", ans);
    }
    return 0;
}

  

时间: 2024-08-09 07:47:53

后缀数组 POJ 2217 Secretary的相关文章

POJ 2217 Secretary (后缀数组)

题目大意: 计算两个字符串的最长的公共字符串字串的长度. 思路分析: 将两个串合并起来. 然后直接跑后缀数组求出height 然后就可以直接扫描一次height ,加个是不是在一个串中的判断就可以了. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define maxn 200005 using namespace std; char str[ma

POJ 2217 Secretary

Secretary Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: 221764-bit integer IO format: %lld      Java class name: Main The basic condition of success of a political party, it is the good Election Programme.

后缀数组 POJ 3581 Sequence

题目链接 题意:把n个数字(A1比其他数字都大)的序列分成三段,每段分别反转,问字典序最小的序列. 分析:因为A1比其他数字都大,所以反转后第一段结尾是很大的数,相当是天然的分割线,第一段可以单独考虑,即求整段的字典序最小的后缀.后面两段不能分开考虑, 例子: 98 4 -1 5 0 5 0 2 3第一步:3 2 0 5 0 5 -1 4 8 对应输出 -1 4 8第二步3 2 0 5 0 5(开始的时候我并没有复制一遍) 对应输出:0 5第三步3 2 0 5    对应输出: 3 2 0 5可

后缀数组 POJ 1743 Musical Theme

题目链接 题意:给定n个数字,求超过5个数字的,最长的,变化相同的,不相交的重复子串 分析:男人8题中的一题!数列相邻两项做差,形成新数列,即求数列中的最长重复子串(不可相交). 后缀数组+二分答案.假如二分得到答案L,如何知道它是可行的呢? 因为对于排序后的后缀,Lcp ( Suffix ( List [ i ] ) , Suffix ( List [ i - 1 ] ) ) 是所有与Suffix ( List [ i ] )的LCP值中最大的一个. 因为 Height [ i ] 表示的是排

[贪心+后缀数组] poj 3623 Best Cow Line, Gold

题意: 给N个字符,每次只能取第一个或者最后一个,问构成最小字典序的串是什么. 思路: 贪心,每次取字典序最小的串,的首字符. 其实就是l和r比较一下构成的串那个字典序小. 这里运用后缀数组要实现O(1)的查询. 将原串反拼进串内做da. 然后根据ra判断. 代码: #include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include&quo

后缀数组 POJ 3261 Milk Patterns

题目链接 题意:可重叠的 k 次最长重复子串.给定一个字符串,求至少出现 k 次的最长重复子串,这 k 个子串可以重叠. 分析:与POJ 1743做法类似,先二分答案,height数组分段后统计 LCP>=m 的子串的个数. #include <cstdio> #include <cstring> #include <algorithm> const int N = 2e4 + 5; int sa[N], rank[N], height[N]; int t[N],

后缀数组 poj 3415

首先,height[i]-k+1  很好理解把,他是说明目前这对后缀中不小于k的公共子串个数. 题解说用单调栈维护,为什么要用单调栈维护呢?因为时间复杂的可以大大降低. 怎么个降低方法呢? 在之前学习lcp(就是height数组)的时候,肯定接触过这样一个问题,就是从i开始的后缀字符串跟从j开始的后缀字符串的最长公共前缀. 计算方法是:取height[rank[i]+1]~height[rank[j]]的最小值 利用上面这个性质来维护单调递增的栈. 借助我看的那篇博客上面说的: 为什么要这样呢?

后缀数组 POJ 3693 Maximum repetition substring

题目链接 题意:给定一个字符串,求重复次数最多的连续重复子串. 分析:(论文上的分析)先穷举长度 L,然后求长度为 L 的子串最多能连续出现几次.首先连续出现 1 次是肯定可以的,所以这里只考虑至少 2 次的情况.假设在原字符串中连续出 现 2 次,记这个子字符串为 S,那么 S 肯定包括了字符 r[0], r[L], r[L*2], r[L*3], ……中的某相邻的两个.所以只须看字符 r[L*i]和 r[L*(i+1)]往前和 往后各能匹配到多远,记这个总长度为 K,那么这里连续出现了 K/

后缀数组 POJ 3974 Palindrome &amp;&amp; URAL 1297 Palindrome

题目链接 题意:求给定的字符串的最长回文子串 分析:做法是构造一个新的字符串是原字符串+反转后的原字符串(这样方便求两边回文的后缀的最长前缀),即newS = S + '$' + revS,枚举回文串中心位置,RMQ询问LCP = min (height[rank[l]+1] to height[rank[r]]),注意的是RMQ传入参数最好是后缀的位置,因为它们在树上的顺序未知,且左边还要+1. #include <cstdio> #include <algorithm> #in