spoj LCS 后缀自动机

链接:http://www.spoj.com/problems/LCS/

题意两串LCS

确实没什么好说的,第一次编嘛。把网上的教程斗翻出来看一遍就好了。

另发现,百度内部用户交流使用的图片在百度快照中看得到。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 2510000
#define MAXT MAXN*2
struct SAM_node
{
        int pnt,len;
        int nxt[26];
        void Print(int id=-1)
        {
                printf("-----------------\n");
                printf("Sam id:%d\n",id);
                printf("Next :\n");
                for (int i=0;i<26;i++)
                        printf("[%c:%d];",i+‘a‘,nxt[i]);
                printf("\n");
                printf("Parent:%d\n",pnt);
                printf("Length:%d\n",len);
        }
}sam[MAXT];
int last=1;
int topt=1;
void Add_item(char ch)
{
        int p,np;
        p=last;
        np=++topt;
        sam[np].len=sam[p].len+1;
        while (p && !sam[p].nxt[ch-‘a‘])
                sam[p].nxt[ch-‘a‘]=np,p=sam[p].pnt;
        if (!p)
        {
                sam[np].pnt=1;
                last=np;
        }else
        {
                int q=sam[p].nxt[ch-‘a‘];
                if (sam[q].len==sam[p].len+1)
                        sam[np].pnt=q;
                else
                {
                        int nq;
                        nq=++topt;
                        sam[nq]=sam[q];
                        sam[nq].len=sam[p].len+1;
                        sam[nq].pnt=sam[q].pnt;
                        sam[q].pnt=nq;
                        sam[np].pnt=nq;
                        while (p && sam[p].nxt[ch-‘a‘]==q)
                        {
                                sam[p].nxt[ch-‘a‘]=nq;
                                p=sam[p].pnt;
                        }
                }
                last=np;
        }
}

char str[MAXN];
char str2[MAXN];
int main()
{
        freopen("input.txt","r",stdin);
        scanf("%s",str);
        int n=strlen(str);
        for (int i=0;i<n;i++)
                Add_item(str[i]);
        for (int i=0;i<=topt;i++)
        {
                //sam[i].Print(i);
        }
        scanf("%s",str2);
        int now=1,res=0,ans=0;
        int m=strlen(str2);
        for (int i=0;i<m;i++)
        {
                if (sam[now].nxt[str2[i]-‘a‘])
                {
                        now=sam[now].nxt[str2[i]-‘a‘];
                        res++;
                        ans=max(ans,res);
                }else
                {
                        while (now && !sam[now].nxt[str2[i]-‘a‘])
                                now=sam[now].pnt;
                        if (!now)
                        {
                                now=1;
                                res=0;
                        }
                        else
                        {
                                res=sam[now].len+1;
                                now=sam[now].nxt[str2[i]-‘a‘];
                                ans=max(ans,res);
                        }
                }
        }
        printf("%d\n",ans);
}
时间: 2024-11-02 17:12:05

spoj LCS 后缀自动机的相关文章

SPOJ LCS 后缀自动机找最大公共子串

这里用第一个字符串构建完成后缀自动机以后 不断用第二个字符串从左往右沿着后缀自动机往前走,如能找到,那么当前匹配配数加1 如果找不到,那么就不断沿着后缀树不断往前找到所能匹配到当前字符的最大长度,然后将cur节点转移到当前节点即可,再把答案加1 记住不断更新所能得到的最大值 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using

SPOJ - NSUBSTR 后缀自动机板子

SPOJ - NSUBSTR #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PII pair<int, int> #define PLI pair<LL, int> #define PDD pair<double,double> #define ull unsigned long long

spoj 1811 LCS - Longest Common Substring (后缀自动机)

spoj 1811 LCS - Longest Common Substring 题意: 给出两个串S, T, 求最长公共子串. 限制: |S|, |T| <= 1e5 思路: dp O(n^2) 铁定超时 后缀数组 O(nlog(n)) 在spoj上没试过,感觉也会被卡掉 后缀自动机 O(n) 我们考虑用SAM读入字符串B; 令当前状态为s,同时最大匹配长度为len; 我们读入字符x.如果s有标号为x的边,那么s=trans(s,x),len = len+1; 否则我们找到s的第一个祖先a,它

SPOJ LCS Longest Common Substring(后缀自动机)题解

题意: 求两个串的最大\(LCS\). 思路: 把第一个串建后缀自动机,第二个串跑后缀自动机,如果一个节点失配了,那么往父节点跑,期间更新答案即可. 代码: #include<set> #include<map> #include<cmath> #include<queue> #include<bitset> #include<string> #include<cstdio> #include<vector>

spoj 1812 LCS2 - Longest Common Substring II (后缀自动机)

spoj 1812 LCS2 - Longest Common Substring II 题意: 给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串. 限制: 1 <= n <= 10 |A[i]| <= 1e5 思路: 和spoj 1811 LCS差不多的做法 把其中一个A建后缀自动机 考虑一个状态s, 如果A之外的其他串对它的匹配长度分别是a[1], a[2], ..., a[n - 1], 那么min(a[1], a[2], ..., a[n - 1]

【后缀自动机】SPOJ 1812-LCSII

题意: 给出最多10个长度不超过100000的字符串,求他们的LCS的长度.时限是鬼畜的0.25s . 后缀自动机练习...虽然有人这么说但我并不觉得hash能过. 本题可以说是[论SAM中按step排序更新pre的重要性]: 总的来说做法和1811-LCS有点类似,不同的是因为有多个字符串,因此每个字符串都需要在SAM上跑一次. 记录下每个节点最长能容纳长度为多少的字符,最后取个MAX就行了. 用nans[i]表示匹配当前字符串时,i号点能容纳的子串长度,如果i的pre上的当前答案比i还要小的

SPOJ 1812 Longest Common Substring II(后缀自动机)

[题目链接] http://www.spoj.com/problems/LCS2/ [题目大意] 求n个串的最长公共子串 [题解] 对一个串建立后缀自动机,剩余的串在上面跑,保存匹配每个状态的最小值, 取最小值中的最大值即可.由于跑的地方只记录了匹配结尾的状态, 所以还需要更新parent树上的状态,既然匹配到了子节点, 那么parent树链上的值就都能够取到l, 一开始给每个不同状态按照l从小到大分配储存地址, 这样,我们就可以从匹配长度最长的开始更新parent树的情况. [代码] #inc

【SPOJ】8222. Substrings(后缀自动机)

http://www.spoj.com/problems/NSUBSTR/ 题意:给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值.求F(1)..F(Length(S)) 这题做法: 首先建立字符串的后缀自动机. 因为自动机中的每个状态都代表一类子串前缀,且任意状态的最长的|max|所对应的子串是唯一的. 所以我们算出每个子串(即找到的状态是end态),他们的right值为++(即保证长度为当前子串的出现次数为1),然后自底向上在parent树中更新right值(pare

【后缀自动机】SPOJ 8222-最多重复子串

题意: 一个长度不超过250000的字符串,求出它长度为i的子串最多出现了多少次. 后缀自动机练习题...虽说是用Cube评测的不过时限仍然鬼畜. 考虑SAM的性质: 一个串的SAM肯定可以接受这个串的所有子串.SAM上的每一个点代表了一个子串. 主链:SAM上最长的那条链,也就是说从根走到主链的尾端就是整个字符串. 用t[i]记录i号点表示的子串的出现次数,沿着主链走一遍,很明显,主链上所有的点都代表了一个前缀,每个前缀都出现过.因此主链上的点的t初始值为1. 接着,之前提到过,一个点的pre