POJ - 2774-Long Long Message-( 后缀数组 / 后缀自动机 / 二分 + 哈希 )

字符串hash + 二分答案 - 求最长公共子串 --- poj 2774 Long Long Message Problem's Link:http://poj.org/problem?id=2774   Mean:   求两个字符串的最长公共子串的长度。 analyse:  前面在学习后缀数组的时候已经做过一遍了,但是现在主攻字符串hash,再用字符串hash写一遍。 这题的思路是这样的: 1)取较短的串的长度作为high,然后二分答案(每次判断长 阅读详情
题目链接:点击进入
题目

在这里插入图片描述
在这里插入图片描述

题意

求两个字符串最长连续公共子串的长度。

思路1:后缀数组

定义以 s 的第 i 个字符为第一个元素的后缀为 suff ( i ) ;
定义 LCP ( i , j ) 为 suff ( sa [ i ] ) 与 suff ( sa [ j ] ) 的最长公共前缀 ;
LCP的几条性质:
1、LCP ( i , j ) = LCP ( j , i ) ;
2、LCP ( i , i ) = len ( sa [ i ] ) = n - sa [ i ] + 1 ;
2、LCP ( i , k ) = min ( LCP ( i , j ) , LCP ( j , k ) ) 对于任意 1<= i <= j <= k <= n ;
4、LCP ( i , k ) = min ( LCP ( j , j - 1 ) ) 对于任意 1 < i <= j <= k <= n ;
5、LCP ( i , k ) = min ( height [ j ] ) i + 1 <= j <= k ;
height [ i ] 为 LCP ( i , i - 1 ) ,1 < i <= n ( height [ 1 ] = 0 )
字符串的任何一个子串都是这个字符串的某个后缀的前缀。求字符串 S 和 T 的最长连续公共子串相当于求 S 的后缀和 T 的后缀的最长公共前缀的最大值。如果暴力枚举 S 和 T 的全部后缀求最大LCP,那么效率会很低。可以将 S 和 T 合成一个字符串 A ( 中间用一个没有出现过的字符隔开,方便排序后求最长连续公共子串 ),然后求 A 的后缀数组,求出 height 数组,同时不是所有的 height 值都是符合要求的,要保证 suffix ( sa [ i - 1 ] ) 和 suffix ( sa [ i ] ) 分别是 S 和 T 两个字符串中的后缀,这样的 height 值才可以更新答案。

代码1
#include<iostream>
#include<string>
#include<map>
#include<set>
//#include<unordered_map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<fstream>
#define X first
#define Y second
#define best 131 
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define lowbit(x) x & -x
#define inf 0x3f3f3f3f
//#define int long long
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps=1e-7;
const double pai=acos(-1.0);
const int N=2e4+10;
const int maxn=1e6+10;
const int mod=1e9+7;
int y[maxn],x[maxn],c[maxn],sa[maxn],rk[maxn],height[maxn],dmin[maxn][20];;
int n,m;
char s[maxn],t[maxn];
void get_sa() 
{
	for(int i=1;i<=n;++i) ++c[x[i]=s[i]];
	for(int i=2;i<=m;++i) c[i]+=c[i-1];
	for(int i=n;i>=1;--i) sa[c[x[i]]--]=i;
	for(int k=1;k<=n;k<<=1) 
	{
		int num=0;
		for(int i=n-k+1;i<=n;++i) y[++num]=i;
		for(int i=1;i<=n;++i) if(sa[i]>k) y[++num]=sa[i]-k;
		for(int i=1 ;i<=m;++i) c[i]=0;
		for(int i=1;i<=n;++i) ++c[x[i]];
		for(int i=2;i<=m;++i) c[i]+=c[i-1]; 
		for(int i=n;i>=1;--i) sa[c[x[y[i]]]--]=y[i],y[i]=0;
		swap(x,y);x[sa[1]]=1;num=1;
		for(int i=2;i<=n;++i)
			x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
		if(num==n) break;
		m=num;
	}
}
void get_height() 
{
	int k=0;
	for(int i=1;i<=n;++i) rk[sa[i]]=i;
	for(int i=1;i<=n;++i) 
	{
		if(rk[i]==1) continue;
		if(k) k--;
		int j=sa[rk[i]-1];
		while(j+k<=n&&i+k<=n&&s[i+k]==s[j+k]) k++;
		height[rk[i]]=k;
	}
}
void initMin()
{
    for(int i=1;i<=n;i++) dmin[i][0]=height[i];
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            dmin[i][j]=min(dmin[i][j-1] , dmin[i+(1<<(j-1))][j-1]);
}
int RMQ(int L,int R)//取得范围最小值
{
    int k=0;
    while((1<<(k+1))<=R-L+1)k++;
    return min(dmin[L][k] ,dmin[R-(1<<k)+1][k]);
}
int LCP(int i,int j)//求后缀i和j的LCP最长公共前缀
{
    int L=rk[i],R=rk[j];
    if(L>R) swap(L,R);
    L++;
    return RMQ(L,R);
}
int main() 
{
	cin>>s+1>>t+1;
	int l1=strlen(s+1);
    int l2=strlen(t+1);
    s[l1+1]=125;
    for(int i=1;i<=l2;i++)
    	s[l1+i+1]=t[i];
    n=l1+l2+1;m=140;
    get_sa(); 
    get_height();
    int maxx=0;
    for(int i=2;i<=n;i++)
    {
        if(height[i]>maxx)
        {
            int a=sa[i-1];
            int b=sa[i];
            if(a>0&&a<=l1+1&&b>l1+1)
                if(height[i]>maxx) 
					maxx=height[i];
            if(b>0&&b<=l1+1&&a>l1+1)
                if(height[i]>maxx) 
					maxx=height[i];
        }
    }
    cout<<maxx<<endl;
    return 0;
}
思路2:二分+哈希

最长公共子串存在单调性: 如果两个串存在长度为 k 的公共子串,那么必然存在长度 0 到 k -1 的公共子串。
根据单调性,二分求最长公共子串长度,然后 O ( n ) 算出两个串长度为 len 的子串的哈希值,然后排序+二分查找是否存在相同的哈希值( 即公共子串 )

代码2
#include<iostream>
#include<string>
#include<map>
#include<set>
//#include<unordered_map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<fstream>
#define X first
#define Y second
#define base 131 
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define lowbit(x) x & -x
#define inf 0x3f3f3f3f
//#define int long long
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps=1e-7;
const double pai=acos(-1.0);
const int N=2e4+10;
const int maxn=1e6+10;
const int mod=1e9+7;
int n,m,k,cnt,tot,l1,l2;
ull h1[maxn],h2[maxn],p[maxn],ans,h[maxn];
char s[maxn],t[maxn];
void hash_init() 
{
	p[0]=1;h1[0]=0;h2[0]=0;
	for(int i=1;i<=max(l1,l2);i++)
		p[i]=p[i-1]*base;
	for(int i=1;i<=l1;i++)
		h1[i]=h1[i-1]*base+s[i];
	for(int i=1;i<=l2;i++)
		h2[i]=h2[i-1]*base+t[i];	
}
ull hash_code(int l, int r,int op)
{
	if(op==1)
		return h1[r]-h1[l-1]*p[r-l+1];
	else
		return h2[r]-h2[l-1]*p[r-l+1];
}
bool check(int len)  //检查长度为len的公共子串是否存在
{
	for(int i=len;i<=l1;i++)    
	   h[i-len]=hash_code(i-len+1,i,1);//算出字符串 s 中所有区间[i,i+len-1]的子串哈希值,保存并排序
	sort(h,h+l1-len+1);
	for(int i=len;i<=l2;i++)
		if(binary_search(h,h+l1-len+1,hash_code(i-len+1,i,2))) //算出字符串 t 中所有区间[i,i+len-1]的子串哈希值
			return 1;                                         //并在数组 h 中二分查找是否有相同的值,若有则存在长度为len的公共子串
	return 0;
}
int main() 
{
	cin>>s+1>>t+1;
	l1=strlen(s+1),l2=strlen(t+1);
	hash_init();
	int l=1,r=min(l1,l2);
	while(l<=r)//二分求最长公共子串长度
	{                     
		int mid=l+r>>1;
		if(check(mid))
		{
            ans=mid;
            l=mid+1;
		}
		else r=mid-1;
	}
	cout<<ans<<endl;
    return 0;
}

思路3:后缀自动机

( 记录模板 )

代码3
#include<iostream>
#include<string>
#include<map>
#include<set>
//#include<unordered_map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<fstream>
#define X first
#define Y second
#define base 131 
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define lowbit(x) x & -x
#define inf 0x3f3f3f3f
//#define int long long
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps=1e-7;
const double pai=acos(-1.0);
const int N=2e4+10;
const int maxn=1e6+10;
const int mod=1e9+7;
int par[maxn<<1],son[maxn<<1][30];
int deep[maxn<<1],cnt,root,last,x,l1,l2,sum,ans;
char s[maxn],t[maxn];
void SAM(int ch)
{
	int u=last;
	deep[++cnt]=deep[last]+1,last=cnt;
	while(u&&!son[u][ch]) son[u][ch]=last,u=par[u];
	if(!u) par[last]=root;
	else 
	{
		int v=son[u][ch];
		if(deep[v]==deep[u]+1) par[last]=v;
		else 
		{
			deep[++cnt]=deep[u]+1;
			int next=cnt;
			memcpy(son[next],son[v],sizeof(son[v]));
			par[next]=par[v],par[v]=par[last]=next;
			while(u&&son[u][ch]==v) son[u][ch]=next,u=par[u];
		}
	}
}
int main() 
{
	cin>>s+1>>t+1;
	l1=strlen(s+1),l2=strlen(t+1);
	deep[++cnt]=0;x=root=last=cnt;
	for(int i=1;i<=l1;i++) SAM(s[i]-'a');
	for(int i=1;i<=l2;i++)
	{
		if(son[x][t[i]-'a']) x=son[x][t[i]-'a'],sum++;
		else 
		{
			while(x&&son[x][t[i]-'a']==0) x=par[x];
			if(!x) x=root,sum=0;
			else sum=deep[x]+1,x=son[x][t[i]-'a'];
		}
		ans=max(ans,sum);
	}
	cout<<ans<<endl;
    return 0;
}

VS配置RTKLIB(卫星定位开源代码)环境 @RTKlib代码调试教程-Visual Studio 2019 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。 ##RTKLIB-rtklib_2.4.3 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 @RTKlib代码调试教程-Visual Studio 2019 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技 阅读详情

相关推荐

金融数据自动化:从同花顺API到Excel的智能转换之旅

本文详细介绍了如何利用同花顺API实现金融数据自动化处理,并将其智能转换为Excel格式的全流程。通过Python编程和Excel高级技巧,读者可以掌握从数据获取、清洗到输出的完整解决方案,大幅提升金融数据分析的效率和准确性。文章特别强调了同花顺API的使用技巧和Excel自动化输出的最佳实践。

sql99的博客 461

POJ 2774 Long Long Message 后缀数组/后缀自动机

用分隔符连接2个字符串,并且跨字符串的height才对答案有贡献。 回忆一下当时的程序。。#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define rep(i,j,k) for(i=j;i<k;i++) #define MAXN 200050int n, num[MAXN], z[M

とある黄鱼のOIブログ 601

告别高延迟!用RV1106+4G模块+libdatachannel搭建低功耗WebRTC监控,保姆级避坑指南

本文详细介绍了如何利用RV1106低功耗处理器、4G模块和libdatachannel库构建嵌入式WebRTC监控系统,解决高延迟问题。通过硬件选型、系统优化和核心代码实现,提供了一套完整的低功耗实时视频传输方案,特别适合智能安防和工业物联网应用。

weixin_42527401的博客 192

POJ 2774 Long Long Message —— 后缀自动机求两个串的最长公共子串

This way 题意: 给你两个串,问你他们的最长公共子串的长度为多少 题解: 后缀自动机,大致细节我都写在注释里面了 #include<iostream> #include<stdio.h> #include<cstring> using namespace std; #define ll long long const int N = 2e5+1000; ...

天翼之城的博客 369

MOSFET热失效机理与保护电路设计:实战案例

深入解析MOSFET工作原理及其在高温下的失效机制,结合实际案例探讨有效保护电路设计,提升系统可靠性与安全性。

weixin_28713083的博客 850

【第一篇】Xshell连接服务器部署前后端项目(连接服务器)

利用Xshell连接服务器部署前后端项目

blog 1073

Long Long Message poj 2774 哈希+二分

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 getting ill. Being worried about spending so much on railway tickets (Byt...

Top_Spirit的博客 467

STM32开发者必看:如何在正点原子探索者开发板上快速移植CANopenNode协议栈

本文为STM32开发者提供了在正点原子探索者开发板上快速移植CANopenNode协议栈的实战指南。文章详细介绍了从环境准备、硬件抽象层适配到协议栈初始化与测试的全过程,并分享了PDO配置与性能优化等关键技巧,帮助开发者高效实现CANopen标准化通信。

weixin_29173777的博客 462

POJ2217 Secretary、POJ2774 Long Long Message - 最长公共子串 - 字符串哈希+二分/后缀数组

Secretary、Long Long Message     题目大概意思: 给出两个字符串 S,TS,TS,T ,求 SSS 与 TTT 的最大公共子串的长度。其中 S,TS,TS,T 的长度均不超过 10510^5105 .   样例输入 yeshowmuchiloveyoumydearmotherreallyicannotbelieveit yeaphowmu...

太阳升起 329

GoAnywhere MFT 身份验证绕过漏洞(CVE-2024-0204)

GoAnywhere MFT 身份验证绕过漏洞(CVE-2024-0204)

weixin_43567873的博客 387

深度学习在地质勘探中的应用:使用Python构建卷积神经网络进行地震数据分析

在本文中,我们介绍了如何利用深度学习技术,特别是卷积神经网络(CNN),来处理和分析地震数据。我们使用了Python编程语言和TensorFlow框架构建了一个CNN模型,并使用地震数据进行了训练和评估。在本文中,我们将探讨如何利用深度学习技术,特别是卷积神经网络(CNN),来处理和分析地震数据。首先,我们需要获取地震数据集。通过本文的介绍,希望您能对深度学习在地质勘探领域的应用有更深入的了解,并能够应用这些技术来解决实际问题。在准备好地震数据和构建CNN模型后,我们需要将数据分为训练集和测试集。

斌擎科技 1472

poj 2774 Long Long Message

本题是求解最长公共子串,解法有两种,第一种是二分+ 哈希,第二种是后缀数组。 下面介绍后缀数组的解法。 将两个字符串用分隔符28连接起来,末尾补0,那么只需要求出这个字符串的后缀数组和height数组,找到起点分别在两个字符串的最大的height值即答案。 AC代码: #include #include using namespace std; const int N = 2000

思维迷宫 495

PyTorch深度学习实战(1)——神经网络与模型训练过程详解

在本节中,我们将了解传统机器学习与人工神经网络间的差异,并了解如何在实现前向传播之前连接网络的各个层,以计算与网络当前权重对应的损失值;实现反向传播以优化权重达到最小化损失值的目标。并将实现网络的所有关键组成——前向传播、激活函数、损失函数、链式法则和梯度下降,从零开始构建并训练了一个简单的神经网络。

盼小辉丶的博客 9万+

【POJ】2774 - Long Long Message(HASH + 二分)

题目连接 题意:给出两个字符串,求出它们的最长公共子串(Longest Common Substring) 分析: 如果两个串的长度在1e3的话,可以直接DP。但是这道题的长度在1e5,一定会超时加爆内存,改变思路。发现hash可以做,同时需要两次二分,第一次二分LCS的长度,第二次二分查找是否有满足的值。 AC代码: #include&amp;lt;stdio.h&amp;gt; #i...

Dicer_的博客 435

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

poj 2774

Long Long Message Time Limit:4000MS Memory Limit:131072K Total Submissions:36765 Accepted:14741 Case Time Limit:1000MS Description The little cat is majoring ...

weixin_30642267的博客 81

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

POJ2774 Long Long Message —— 后缀数组 两字符串的最长公共子串

题目链接:https://vjudge.net/problem/POJ-2774 Long Long Message Time Limit:4000MS Memory Limit:131072K Total Submissions:33144 Accepted:13344 Case Time Limit:1000MS...

weixin_30908103的博客 103

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

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 ...

weixin_30852367的博客 104

POJ-2774

Description Little cat在Byterland的首都读物理专业。这些天他收到了一条悲伤地信息:他的母亲生病了。担心买火车票花钱太多(Byterland是一个巨大的国家,因此他坐火车回家需要16小时),他决定只给母亲发短信。Little cat的家境并不富裕,因此他经常去营业厅查看自己发短信花了多少钱。昨天营业厅的电脑坏掉了,打印出两条很长的信息。机智的little...

weixin_30657541的博客 215

字符串哈希专题

layout: post title: 字符串哈希专题 author: "luowentaoaa" catalog: true tags: mathjax: true - 字符串 传送门 A.POJ - 1200 A - Crazy Search 摘要 哈希进制转换 题意 一个字符串分成长度为N的字串。且不同的字符不会超过NC个。问总共有多少个不同的子串 思路 以nc作为进制,把一个子串化为这...

weixin_30242907的博客 207

POJ字符串学习笔记

POJ 字符串

whjk20的专栏 624

字符串专题小结

字符串专题算是搞得差不多了,来大概总结一下吧。 要掌握的算法: 1、KMP算法 作用是两个串之间的匹配,核心思想是pre[i]表示串B的最长的前缀与以i为结尾的后缀相同,每次匹配失败时,从i跳到pre[i]就可以了。 2、trie树 作用是存储许多个串,核心思想是除根节点每个点表示一个字母,从根节点到每个点的路径表示一个字符串,单词节点打上标记 3、AC自动机 作用是

Oxer的专栏 2176

poj 1064 java_poj 1064(二分答案)

题意:有N条绳子,长度分别为 length[1,2,3,........,N]。如果从它们中切割出K条长度相同的绳子,这K条绳子每条最长有多长?结果保留两位小数。题解:二分可能的长度。AC代码:精度问题:#include#include#includeusing namespace std;const int maxn=1e4+;int N,K;double length[maxn];bool C...

weixin_28973649的博客 440

ACM字符串题目总结

POJ 1002 - 487-3279(基础) http://acm.pku.edu.cn/JudgeOnline/problem?id=1002 题意:略 解法:二叉查找数,map,快排... POJ 1200 - Crazy Search(基础) http://acm.pku.edu.cn/JudgeOnline/problem?id=1200 题意:找出不相...

weixin_30416497的博客 181

字符串的题目

POJ 1002 - 487-3279(基础) http://acm.pku.edu.cn/JudgeOnline/problem?id=1002 题意:略 解法:二叉查找数,map,快排... POJ 1200 - Crazy Search(基础) http://acm.pku.edu.cn/JudgeOnline/problem?id=1200 题意:找出不相同的子串数量,字母表大小和子串长度会给定,这题很推荐hash入门者一做 解法:hash(建议karp-rabin) POJ 120

mindmb的专栏 787

字符串练习

poj pku字符串题目推荐及解题报告 POJ 1002 - 487-3279(基础) http://acm.pku.edu.cn/JudgeOnline/problem?id=1002 题意:略 解法:二叉查找数,map,快排... POJ 1200 - Crazy Search(基础) http://acm.pku.edu.cn/JudgeOnline/

终究我要华丽逆袭 1055

[汇总]字符串题目推荐及解题报告

说明:小弟才疏学浅,最近发现此文点击率较高,还有一些转载,实在是万分惭愧。这份题目推荐里面,实在水题烂题太多,上不得台面,等今年赛区赛结束后,本菜一定好好清理下此贴。POJ 1002 - 487-3279(基础)http://acm.pku.edu.cn/JudgeOnline/problem?id=1002题意:略解法:二叉查找数,map,快排...POJ 1200 - Crazy Se

linleiqin 440
上一篇: 2021牛客寒假算法基础集训营1-E-三棱锥之刻-(计算几何)
下一篇: P3809 【模板】后缀排序
Cosmic_Tree
博客等级 码龄7年 134粉丝 337原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值