POJ2774 Long Long Message 【SAM】

POJ2774 Long Long Message

找两个串的最长公共字串

对其中一个串\(s\)建\(SAM\),然后我们如何找到最长公共字串,办法就是枚举\(t\)串所有的前缀,然后找各个前缀的最长能和\(s\)串匹配的后缀。

如果一个个跑需要\(O(n^2)\),\(SAM\)可以来保存之前匹配的状态,假设现在匹配的状态是\(u\),匹配到的最长后缀长度为\(l\),那么现在考虑在当前状态后面加上一个字符,也就是成为\(t\)串一个新的前缀,那么最大能匹配的必然是在上一次匹配到的最长串的基础上去匹配,所以我们可以不断判断\(u\)这个状态是否有连向新加入的字符的边,如果有的话,更新\(u,l \Rightarrow u = ch[u][c]; l+=1\),如果没有的话,就要跑当前状态的后缀链接,找到最长的\(endpos\)不同的之前匹配串的一个后缀,然后更新\(u,l \Rightarrow u = link[u]; l = len[u]\),直到遇到有连边的状态或者到了初始点。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<string>
#include<algorithm>
#include<stack>
using namespace std;
void ____(){ ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0); }
const int MAXN = 2e5+7;
char s[MAXN];
struct SAM{
    int len[MAXN],link[MAXN],ch[MAXN][26],last,tot;
    void init(){ link[tot = last = 0] = -1; memset(ch[0],0,sizeof(ch[0])); }
    void extend(int c){
        int np = ++tot; memset(ch[tot],0,sizeof(ch[tot]));
        int p = last; len[np] = len[last] + 1;
        while(p!=-1 and !ch[p][c]){
            ch[p][c] = np;
            p = link[p];
        }
        if(p==-1) link[np] = 0;
        else{
            int q = ch[p][c];
            if(len[p]+1==len[q]) link[np] = q;
            else{
                int clone = ++tot;
                len[clone] = len[p] + 1;
                link[clone] = link[q];
                for(int i = 0; i < 26; i++) ch[clone][i] = ch[q][i];
                link[np] = link[q] = clone;
                while(p!=-1 and ch[p][c]==q){
                    ch[p][c] = clone;
                    p = link[p];
                }
            }
        }
        last = np;
    }
    int lcs(char *str){
        int ret = 0, u = 0, l = 0, n = strlen(str);
        for(int i = 0; i < n; i++){
            int c = str[i] - ‘a‘;
            while(u and !ch[u][c]){
                u = link[u];
                l = len[u];
            }
            if(ch[u][c]) u = ch[u][c], l++;
            ret = max(ret,l);
        }
        return ret;
    }
}sam;
int main(){
    while(scanf("%s",s)!=EOF){
        sam.init(); int n = strlen(s);
        for(int i = 0; i < n; i++) sam.extend(s[i]-‘a‘);
        scanf("%s",s);
        printf("%d\n",sam.lcs(s));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/kikokiko/p/12698595.html

时间: 2024-10-27 13:16:14

POJ2774 Long Long Message 【SAM】的相关文章

【SAM】BZOJ2882-工艺

[题目大意] 求一个循环数列的最小表示法. [思路] SAM乱搞,和前面的POJ那道一样.然而MLE了,当作学习一下map的用法^ ^ map的使用方法(来源:☆) 一.map的说明    1   头文件   #include   <map>     2   定义   map<string,   int>   my_Map;   或者是typedef     map<string,   int>   MY_MAP;   MY_MAP   my_Map;     3   

【SAM】codevs3160-最长公共子串

[题目大意] 求两个字符串的最长公共子串. [思路] 对第一个字符串建立后缀自动机,第二个字符串去匹配.cnt记录当前最长公共子串的长度,而ret记录答案. p代表位置指针,初始在rt位置. 对于第二个字符串的某一位s[i],如果当前有s[i]孩子,则cnt+1,继续往后移动:否则沿着pre指针返回.如果pre指针返回到0,则将p回到rt,cnt清空为0;否则如果中间有点拥有s[i]孩子,cnt=step[]+1. 为什么cnt=step[]+1?不要忘了后缀自动机的本质是维护后缀,沿着pre指

POJ 1743 Musical Theme【SAM】

POJ1743 Musical Theme 要找长度\(\ge 5\)且出现次数\(\ge 2\)并且第一次出现和最后一次出现不重叠的最长子串. 题目条件中,如果对于两个串,在一个串的每个数上都加上相同的数之后可以得到另一个串,那么这个两个串可以被是相同的. 首先我们先得到差分数组,然后要求的就是差分数组中长度\(\ge 4\)且出现次数\(\ge 2\)并且第一次出现和最后一次出现不重叠的最长子串 我们需要知道的是每个等价类中终点的最左端和最右端的位置,即(\(firstpos,lastpos

hdu 4119 Isabella&#39;s Message【字符串模拟】

题目链接:http://write.blog.csdn.net/postedit 自我感觉比较麻烦 #include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> #include<string> #include<map> using namespace std; const int maxh=100+10; const int maxe=100

hdu 4119 Isabella&#39;s Message 【字符串处理】

Isabella's Message Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2098    Accepted Submission(s): 614 Problem Description Isabella and Steve are very good friends, and they often write letters

【bugRecord2】selenium.common.exceptions.WebDriverException: Message: &#39;geckodriver&#39; executable needs to be in PATH.

环境信息:Windows7 64位 + python 3.6.5 + selenium 3.11.0 +pyCharm 1 #coding=utf-8 2 from selenium import webdriver 3 driver=webdriver.Firefox() 解决方法: 1.下载geckodriver,路径:https://github.com/mozilla/geckodriver/releases 2.解压后无需安装,将其解压路径配置到环境变量PATH [bugRecord2

laravel 【error】MethodNotAllowedHttpException No message

Symfony \ Component \ HttpKernel \ Exception \ MethodNotAllowedHttpException No message 报错原因[原理]CSRF防护: 在 web 路由文件中所有请求方式为PUT.POST或DELETE的HTML表单都会包含一个CSRF令牌字段,否则,请求会被拒绝 解决办法: 在html表单提交中加入: {{csrf_field()}}或者 <input type="hidden" name="_t

【Python】selenium调用IE11浏览器,报错“找不到元素”NoSuchWindowException: Message:Unable to find element on closed window

当编写自动化脚本,定位浏览器元素时,报如下错误: 代码: >>> # coding=utf-8 >>> from selenium import webdriver >>> driver = webdriver.Ie() >>> driver.get("www.baidu.com") >>> driver.find_element_by_id("kw").send_keys(&

【转】Android实现推送方式解决方案

本文介绍在Android中实现推送方式的基础知识及相关解决方案.推送功能在手机开发中应用的场景是越来起来了,不说别的,就我们手机上的新闻客户端就时不j时的推送过来新的消息,很方便的阅读最新的新闻信息.这种推送功能是好的一面,但是也会经常看到很多推送过来的垃圾信息,这就让我们感到厌烦了,关于这个我们就不能多说什么了,毕竟很多商家要做广告.本文就是来探讨下Android中实现推送功能的一些解决方案,也希望能够起到抛砖引玉的作用.^_^ 1.推送方式基础知识:  在移动互联网时代以前的手机,如果有事情