P2375 题解
我们考虑朴素算法。
显然,我们可以先跑一遍 KMP,计算出每个 的 。
然后,容易发现我们可以暴力跳每一个前缀串的 border,这样可以直接统计出 border 长度 的 border 数量。
回到原题。我们发现上述朴素做法会被 个 拉爆。于是我们考虑优化。
我们能不能考虑把重复的计算节省掉呢?
考虑类似 KMP 的优化。假设当前我们计算到 。
发现,如果我们最大的 的 border 长度为 ,则 一定是 的一个 border。
证明:博主暂时是感性理解。后面补严禁证明。
于是考虑一直使用一个 。复杂度为 。
以下是代码实现:
/*******************************
| Author: DE_aemmprty
| Problem: P1001 A+B Problem
| Contest: Luogu
| URL: https://www.luogu.com.cn/problem/P1001
| When: 2023-12-02 15:30:35
|
| Memory: 512 MB
| Time: 1000 ms
*******************************/
#include <bits/stdc++.h>
using namespace std;
int read() {
char c = getchar();
int x = 0, p = 1;
while ((c < '0' || c > '9') && c != '-') c = getchar();
if (c == '-') p = -1, c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x * p;
}
const int N = 1e6 + 7;
int n;
string s;
int nxt[N], num[N], q[N];
void solve() {
cin >> s;
n = (int) s.size(); s = " " + s;
q[1] = 1;
for (int i = 2, j = 0; i <= n; i ++) {
while (j && s[j + 1] != s[i]) j = nxt[j];
if (s[j + 1] == s[i]) j ++;
nxt[i] = j; q[i] = q[j] + 1;
}
long long ans = 1;
for (int i = 2, j = 0; i <= n; i ++) {
while (j && s[j + 1] != s[i]) j = nxt[j];
if (s[j + 1] == s[i]) j ++;
while (j * 2 > i) j = nxt[j];
(ans *= 1ll * (q[j] + 1)) %= 1000000007;
}
printf("%lld\n", ans);
}
signed main() {
int t = read();
while (t --) solve();
return 0;
}
作者:DE_aemmprty
出处:https://www.cnblogs.com/aemmprty/p/18109215
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库