「 HDU P3336 」 Count the string
2024-09-04 14:37:51
题目大意
给出一个长度为 $n$ 的字符串 $s$ 要求你求出 $s$ 的每一个前缀在 $s$ 中出现的次数之和。$n\le 200000$。
解题思路
暴力的对每一个前缀进行一次匹配,求出出现次数后求和。
那肯定是不行的,复杂的是 $O(n\times (m+n))$ 的,不用想也知道要 TLE 那我们考虑 $KMP$ 中 $next$ 数组的性质:为每一个前缀的前缀和后缀最长的共同子串的长度。
那这不就是说如果 $next[i] = j$ 的话,那么在 $s$ 中 $1\rightarrow j$ 和 $i-next[i]+1\rightarrow i$ 这两个子串是相等的。同时也代表 $1\rightarrow j$ 这个前缀的出现次数多了 $1$。
这就好办了。我们只需要求出 $s$ 的 $next$ 数组,然后就可以算出前缀的出现次数。但是要注意算出的 $next$ 并不能直接求出出现次数。因为 $next$ 数组存储的是位置。所以要一步一步推过来,很容易就能得到一个递推式 $f[i] = f[nxt[i]]+1$ 到最后统计一遍总和就可以得到答案了。
放上代码
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 2e5+, HA = 1e4+;
int T, p, Ans, nxt[maxn], dp[maxn], n;
char s[maxn];
inline void Getnext() {
for(int i=; i<=n; i++) {
p = nxt[i-];
while(p && s[p+] != s[i]) p = nxt[p];
if(s[p+] == s[i]) nxt[i] = p+;
else nxt[i] = ;
}
}
int main() {
scanf("%d", &T);
while (T--) {
memset(nxt, , sizeof(nxt));
memset(dp, , sizeof(dp));
Ans = ;
scanf("%d", &n);
scanf("%s", s+);
Getnext();
dp[] = ;
for(int i=; i<=n; i++) {
dp[i] = dp[nxt[i]] + ;
dp[i] = dp[i] % HA;
}
for(int i=; i<=n; i++)
Ans = (Ans % HA + dp[i] % HA) % HA;
printf("%d\n", Ans);
}
}
最新文章
- backup1
- 【BZOJ 3150】新Nim游戏
- STM32堆栈溢出
- iOS开发UI篇—简单介绍静态单元格的使用
- JSP/SERVLET入门教程--Servlet 使用入门
- java正则表达式 非捕获组详解
- Effective_java之二:慎用重载函数
- Solr初步学习
- java源码剖析: 对象内存布局、JVM锁以及优化
- ajax交互数据简单拼装,数组成字符串
- ●Joyoi Easy
- linux 每个小时释放一次cache
- CGI的工作原理
- 《DenseNet Models for Tiny ImageNet Classification》课程设计论文
- 6 week work 2
- 【javascript】谈谈HTML5: Web-Worker、canvas、indexedDB、拖拽事件
- 《MySQL必知必会》[07] 管理事务处理
- Python3函数式编程
- java中实现Comparable接口实现自定义排序
- 2018.09.27 bzoj3029: 守卫者的挑战(概率dp)
热门文章
- 洛谷P2827 蚯蚓——思路题
- js获取下拉框当前选中的值并弹出
- Tool:CorelDRAW
- linux怎么返回上级目录啊,用cd/命令却这样:bash:cd/:没有那个文件或目录
- 使用inet_ntoa() 时编译提示错误:
- Poj 3177 Redundant Paths (双连通分支+节点统计)
- 数学 FZU 2074 Number of methods
- 全面学习ORACLE Scheduler特性(4)创建和管理Schedule
- 264 Ugly Number II 丑数 II
- Tuple类型的使用