SYZOJ#186 [额]你猜是不是DP

该博客介绍了如何利用哈希和二分查找算法解决字符串处理问题,具体为寻找两个字符串的最长公共连续子串。通过计算每个字符串的哈希前缀,再进行二分查找确定可能的公共子串长度,最终找到最大公共子串的长度。这种方法有效地提高了求解效率。

[额]你猜是不是DP

传送门

题目描述

现在给两个仅包含小写字母的字符串a,b ,求a 与b的最长公共连续子串的长度。

输入格式

两个字符串

输出格式

一个整数,为输入的两个字符串的最长公共连续子串的长度

输入
qaqaaaq
qqaqa
输出
4
解释

最长连续公共子串为qaqa,长度为4


这道题我们只需要把两个字符串的每一个前缀的哈希值求出来,然后二分公共串的长度,如果当前二分到的这个长度 l l l可以找到公共子串,那么我们一定可以找到 l − 1 l-1 l1 l − 2 l-2 l2,……, 1 1 1的公共子串,所以我们往 m i d + 1 → r mid+1 \to r mid+1r二分,其他的情况用 l → m i d − 1 l \to mid-1 lmid1二分,找到一个合适的答案就保存着,这样可以保证我们最后求出来的答案是最大的。

#include <cstdio>
#include <cstdlib>
#include <bits/stdc++.h>
using namespace std;
#define ULL unsigned long long
#define MAXN 200003 
ULL xp[MAXN];
ULL hasha[MAXN], hashb[MAXN];
ULL ha[MAXN], hb[MAXN];
char A[MAXN], B[MAXN];
int x = 233;
int la, lb, mlen, minlen;
bool check(int len)
{
    for(int i = 0; i < la - len + 1; i++)
        hasha[i] = ha[i] - ha[i + len] * xp[len];
    for(int i = 0; i < lb - len + 1; i++)
        hashb[i] = hb[i] - hb[i + len] * xp[len];
    sort(hashb, hashb + lb - len + 1);
    for(int i = 0; i < la - len + 1; i++)
    {
        ULL h = hasha[i];
        int p = lower_bound(hashb, hashb + lb - len + 1, h) - hashb;
        if(p < lb - len + 1 && h == hashb[p])
			return true;
    }
    return false;
}
int main()
{
    scanf("%s %s", A, B);
    la = strlen(A), lb = strlen(B);
    mlen = max(la, lb), minlen = min(la, lb);
    for(int i = la - 1; i >= 0; i--)
        ha[i] = ha[i + 1] * x + A[i];   //哈希前缀
    for(int i = lb - 1; i >= 0; i--)
        hb[i] = hb[i + 1] * x + B[i];   //哈希前缀
	xp[0] = 1;
	for(int i = 1; i <= mlen; i++)
		xp[i] = xp[i - 1] * x;      //前缀
    int l = 0, r = minlen;
    int ans;
    while(l <= r)    //二分长度
    {
        int m = (l + r) >> 1;
        if(check(m))
        {
			ans = m;      //每找到有一个合适的答案就保存下来
			l = m + 1;
    	}
		else
            r = m - 1;
    }
    printf("%d\n", ans);
    return 0;
}
### 关于DP_H头文件的定义和用途 在C语言编程中,`DP_H`通常是一个用于防止重复包含头文件的宏名。这种机制通过条件编译指令实现,确保即使同一个头文件被多次引入到项目中,其内容也只会被编译一次[^1]。 #### 防止重复包含的典型实现方式 以下是常见的防重复包含的代码结构: ```c #ifndef DP_H #define DP_H // 头文件的具体内容声明 #endif /* DP_H */ ``` 在此代码片段中: - `#ifndef DP_H` 检查是否已经定义了名为`DP_H`的宏。 - 如果尚未定义该宏,则执行后续的内容并定义此宏 (`#define DP_H`)。 - 当再次遇到相同的头文件时,由于`DP_H`已经被定义,因此跳过整个文件的内容。 这种方式能够有效避免因多重包含而导致的符号重定义等问题[^2]。 #### DP_H可能的应用场景 虽然具体的功能取决于实际开发需求以及开发者的设计意图,但从命名来看,“DP”可能是某种特定模块或功能缩写(如Data Processing、Display Protocol等),而“_H”则表明这是一个头文件保护符。它主要用于以下方面之一或多者结合: - **数据处理接口**:如果涉及复杂的数据操作逻辑,可能会封装一些通用算法或者工具类方法供其他部分调用; - **显示协议支持**:对于图形界面应用而言,也许包含了绘制元素所需的基础参数设定或者是交互事件处理器等相关描述; - **配置管理平台**:有时也会用来存储应用程序运行期间需要用到的各种设置项集合; 无论确切含义为何种情况,只要遵循上述模式编写即可保障良好的兼容性和扩展性[^3]。 #### 使用示例 假设我们有一个简单的例子展示如何利用这样的防护措施来创建自己的自定义类型定义: ```c /* dp.h */ #ifndef DP_H #define DP_H typedef struct { int id; char name[50]; } DataPoint; void initialize(DataPoint *dp); #endif /* DP_H */ /* dp.c */ #include "dp.h" #include <string.h> void initialize(DataPoint *dp){ memset(dp, 0, sizeof(*dp)); } ``` 在这个小型案例里,当其它源码单元需要访问`DataPoint`结构体或是调用它的初始化函数时只需简单加入一句`#include "dp.h"`便能顺利完成连接工作而不必担心潜在冲突风险存在[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值