【C++】ZZ1864- 解题精讲
【Horn Coding Studio】CPP编程专栏
题目
题目描述
小明刚学习完最长公共前缀(zhui),觉得很有趣。
前缀就是原字符串从左往右的一段连续子字符串。abc的前缀是a, ab, abc。
两个字符串的最长公共前缀就是两个字符串从左往右最长的一段相同的连续子字符串。abc和abd的最长公共前缀是ab。
给小明一个长度为nn的字符串,请求出字符串的每个后缀与其本身的最长公共前缀的长度之和。
前缀就是原字符串从左往右的一段连续子字符串。abc的前缀是a, ab, abc。
两个字符串的最长公共前缀就是两个字符串从左往右最长的一段相同的连续子字符串。abc和abd的最长公共前缀是ab。
给小明一个长度为nn的字符串,请求出字符串的每个后缀与其本身的最长公共前缀的长度之和。
输入
一行一个字符串S。 1=<|S|<=100000。
输出
一行一个整数表示答案。
样例输入 复制
aaa
样例输出 复制
6
提示
样例输入2
qqwqe样例输出2
7
来源
一点即通
字符串的前缀:符号串左部的任意子串(或者说是字符串的任意首部)
字符串的后缀:符号串右部的任意子串(或者说是字符串的任意尾部)
了解完这两个概念后,这两道题使用hash做也就很简单了(怎么可能)
另外,我们还需要用一下二分的方法,毕竟他的数据帆帆,核心代码就像这样:
while(L <= R) { mid = (L + R) >> 1; if(get_hash(1, mid) == get_hash(i, i + mid - 1)) { res = mid; L = mid + 1; }else { R = mid - 1; } }
怎么样?是不是很似曾相识?没错,标准二分欸!
代码
ZZOJ AC
#include<bits/stdc++.h> #define p 13131 using namespace std; int n, has[100005], pn[100005]={1}; char s[100005]; int get_hash(int l, int r) { int ans = (has[r] - has[l-1]*pn[r-l+1]); return (ans); } int main() { for(int i = 1; i <= 100005; i++){ pn[i] = pn[i-1] * p; } scanf("%s", s + 1); n = strlen(s + 1); for(int i = 1; i <= n; i++) { has[i] = (has[i - 1] * p + s[i] - 'a' + 1); } long long ans = n; for(int i = 2; i <= n; i++) { int L = 1, R = n - i + 1, mid, res = 0; while(L <= R) { mid = (L + R) >> 1; if(get_hash(1, mid) == get_hash(i, i + mid - 1)) { res = mid; L = mid + 1; }else { R = mid - 1; } } ans += res; } printf("%lld", ans); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现