目录
一、题目
1、题目描述
2、输入输出
2.1输入
2.2输出
3、原题链接
https://www.luogu.com.cn/problem/P10976
二、解题报告
1、思路分析
注意到 [[s2, n2], m] = [s2, m * n2],所以如果我们可以计算出 [s1, n1] 最多可以得到多少个s2,不妨设为 ans 个,那么最大的 m 就是 floor(ans / m)
如何计算 ans?
如果我们定义 f[i, j] 为 从 i 开始,得到 j 个 s2 所需最少字符数的话,f[i, j] = f[(i + |s1|) % |s1|, j - 1] + f[i, 1]
很经典的阶段性递推,我们考虑倍增加速这个过程:
定义 f[i, j] 为 从 i 开始,得到 2^j 个 s2 所需的最少字符数,那么 f[i, j] = f[i, j - 1] + f[(i + f[i, j - 1]) % |s1|, j - 1]
预处理完f[] 后,我们从 0 出发(从开头出发一定是最优的,因为从中间出发,计算所需字符数还是要加上跳过的字符),从高位到低位贪心的累加f[],即可得到ans
2、复杂度
时间复杂度: O(|s1||s2| + n1 log(n1 |s1| / |s2|))空间复杂度:O(|s1| + |s2| + n1 log(n1 |s1| / |s2|)
3、代码详解
cpp
#include <bits/stdc++.h>
namespace ranges = std::ranges;
namespace views = std::views;
using i64 = long long;
using u32 = unsigned;
using u64 = unsigned long long;
constexpr int B = 30;
constexpr int N = 100;
i64 dp[N][B];
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::string s1, s2;
int n1, n2;
while (std::cin >> s2 >> n2 >> s1 >> n1) {
/*
[[s2, n2], m] = [s2, m * n2]
*/
bool ok = true;
for (int i = 0; i < s1.size(); ++i) {
dp[i][0] = 0;
int cur = i;
for (int j = 0; j < s2.size(); ++j) {
int c = 0;
while (s1[cur] != s2[j]) {
if (++cur == s1.size()) cur = 0;
if (++c > s1.size()) {
ok = false;
break;
}
}
if (!ok) break;
if (++cur == s1.size()) cur = 0;
dp[i][0] += c + 1;
}
if (!ok) break;
}
if (!ok) {
std::cout << 0 << '\n';
continue;
}
for (int j = 0; j + 1 < B; ++j) {
for (int i = 0; i < s1.size(); ++i) {
dp[i][j + 1] = dp[i][j] + dp[(i + dp[i][j]) % s1.size()][j];
}
}
i64 ans = 0, tot = 0;
for (int j = B - 1; j >= 0; --j) {
if (tot + dp[tot % s1.size()][j] <= n1 * s1.size()) {
tot += dp[tot % s1.size()][j];
ans |= 1 << j;
}
}
std::cout << ans / n2 << '\n';
}
return 0;
}


