POJ-2774 后缀数组基础题

POJ 2774

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

总结:搞了半天还是不太理解,看着大神博客强行敲的。。而且还看到有hash+二分做的。

// POJ-2774
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<bitset>
#include<vector>
#include<set>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define F(i,a,b)  for (int i=a;i<b;i++)
#define FF(i,a,b) for (int i=a;i<=b;i++)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
typedef long long ll;
const int N = 3e5+10;

char str[N], str1[N];

//这些应该可以做模板了。。
int wa[N], wb[N], wsf[N], wv[N], sa[N];
int rankn[N], height[N], s[N];
int cmp(int *r, int a, int b, int k)
{
    return r[a]==r[b] && r[a+k]==r[b+k];
}
void Getsa(int *r, int *sa, int n, int m)
{
    int i, j, p, *x=wa, *y=wb, *t;
    F(i,0,m) wsf[i]=0;
    F(i,0,n) wsf[x[i]=r[i]]++;
    F(i,1,m) wsf[i]+= wsf[i-1];
    for(i=n-1; i>=0; i--) sa[--wsf[x[i]]]=i;
    p=1, j=1;
    for( ; p<n; j*=2, m=p) {
        for(p=0, i=n-j; i<n; i++) y[p++]=i;
        F(i,0,n) if(sa[i]>=j) y[p++]=sa[i]-j;
        F(i,0,n) wv[i]=x[y[i]];
        F(i,0,m) wsf[i]=0;
        F(i,0,n) wsf[wv[i]]++;
        F(i,1,m) wsf[i]+= wsf[i-1];
        for(i=n-1; i>=0; i--) sa[--wsf[wv[i]]]=y[i];
        t=x, x=y, y=t;
        x[sa[0]]=0;
        for(p=1, i=1; i<n; i++)
            x[sa[i]]= cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
    }
}
void Getheight(int *r, int n)
{
    int i, j, k=0;
    FF(i,1,n) rankn[sa[i]]=i;
    F(i,0,n) {
        if(k) k--;
        else k=0;
        j=sa[rankn[i]-1];
        while(r[i+k]==r[j+k]) k++;
        height[rankn[i]]=k;
    }
}

int main()
{
    while(~scanf("%s%s", str, str1)) {
        int n=0, len=strlen(str);
        F(i,0,len) s[n++]= str[i]-‘a‘+1;
        s[n++]=28;
        len=strlen(str1);
        F(i,0,len) s[n++]= str1[i]-‘a‘+1;
        s[n]=0;    //把两个字符串并到一起,中间和结尾加上标识符

        Getsa(s, sa, n+1, 30);
        Getheight(s, n);
        int maxn=0, pos=0;
        len=strlen(str);
        F(i,2,n) if(height[i]>maxn) {   //找出一个height值最大并且i与i-1的sa值分别在两串字符中
            if(0<=sa[i-1] && sa[i-1]<len && len<sa[i])
                maxn=height[i];
            if(0<=sa[i] && sa[i]<len && len<sa[i-1])
                maxn=height[i];
        }
        printf("%d\n", maxn);
    }

    return 0;
}
时间: 2024-12-17 10:41:18

POJ-2774 后缀数组基础题的相关文章

POJ 2774 后缀数组:求最长公共子串

思路:其实很简单,就是两个字符串连接起来,中间用个特殊字符隔开,然后用后缀数组求最长公共前缀,然后不同在两个串中,并且最长的就是最长公共子串了. 注意的是:用第一个字符串来判断是不是在同一个字符中,刚开始用了第二个字符的长度来判断WA了2发才发现. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<

poj 2774 Long Long Message 后缀数组基础题

Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 24756   Accepted: 10130 Case Time Limit: 1000MS Description The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to him these days: his mother is ge

POJ 2774 后缀数组

题目链接:http://poj.org/problem?id=2774 题意:给定两个只含小写字母的字符串,求字符串的最长公共子串长度. 思路:根据<<后缀数组——处理字符串的有力工具>>的思路,字符串的任何一个子串都是这个字符串的某个后缀的前缀 .求 A和 B的最长公共子串等价于求 A的后缀和 B的后缀的最长公共前缀的最大值. 如果枚举 A 和 B的所有的后缀,那么这样做显然效率低下.由于要计算 A的后缀和 B的后缀的最长公共前缀, 所以先将第二个字符串写在第一个字符串后面, 中

POJ 2774 后缀数组 || 二分+哈希

Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 35607   Accepted: 14275 Case Time Limit: 1000MS Description The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to him these days

POJ 2774 (后缀数组 最长公共字串) Long Long Message

用一个特殊字符将两个字符串连接起来,然后找最大的height,而且要求这两个相邻的后缀的第一个字符不能在同一个字符串中. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 200000 + 10; 7 8 char s[maxn]; 9 int n; 10 int sa[maxn], rank[maxn],

poj 1743 Musical Theme(男人八题&amp;后缀数组第一题)

Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 17298   Accepted: 5939 Description A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the range 1..88, each representing a key on the

poj 3261 后缀数组 找重复出现k次的子串(子串可以重叠)

题目:http://poj.org/problem?id=3261 仍然是后缀数组的典型应用----后缀数组+lcp+二分 做的蛮顺的,1A 但是大部分时间是在调试代码,因为模板的全局变量用混了,而自己又忘了,,,等西安邀请赛还有四省赛结束之后,该冷静反思下尝试拜托模板了 错误   :1.k用错,题目的k和模板的k用混; 2.还是二分的C()函数,这个其实跟前一篇<poj 1226 hdu 1238 Substrings 求若干字符串正串及反串的最长公共子串 2002亚洲赛天津预选题>的C函数

[poj 2274]后缀数组+最长公共子序列

题目链接:http://poj.org/problem?id=2774 后缀数组真的太强大了,原本dp是n^2的复杂度,在这里只需要O(n+m). 做法:将两个串中间夹一个未出现过的字符接起来,然后做一次后缀数组,得到的height相邻两个排名的后缀,在串中的位置如果满足在分界符左右两侧,就更新最长公共前缀.最后得到的最大值就是最长公共子序列. #include<algorithm> #include<cstdio> #include<cstring> using na

POJ 1226后缀数组:求出现或反转后出现在每个字符串中的最长子串

思路:这题是论文里的最后一道练习题了,不过最后一题竟然挺水的. 因为求的是未反转或者反转后,最长公共子串. 刚开始还真不知道怎么构建连接成一个字符串,因为需要有反转嘛! 但是其实挺简单的,把未反转的和反转后的字符串都连起来,中间用未出现过的字符隔开就行了!然后未反转的和反转的在同一组. 二分枚举最长的公共前缀长度,然后统计看看这个最长的长度在不在所有的组里,如果在就符合-- #include<iostream> #include<cstdio> #include<cstrin