计算重复题解
计算重复(acwing 294)
这题的话我们很好想到暴力的做法,这个最终的满足的式子其实是一个幌子,这里只需要求最大的 p
使得 conn(s2,p) 能由 conn(s1,n1) 生成 。输出 \(p/n2\)
如何求这个最大值?像如果你直接让s1 一个一个对过来理论来说是可以的,但是时间复杂度还是爆炸的。
这里可以想想如何更好的暴力,直接由 s2 的任意一个点开始,看 s1 最多能匹配的长度。
那这样的时间复杂度应该是比较大的。
我们发现每次匹配都是相同的,没有区别,这样不就刚好就是倍增的特征吗?直接倍增即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 105, M = 40;
string s1, s2;
long long n1, n2, f[N][M + 5];
void dp() {
for (int i = 0; i < s1.size(); ++i) {
int pos = i;
f[i][0] = 0;
for (int j = 0; j < s2.size(); ++j) {
int cnt = 0;
while (s1[pos] != s2[j]) {
pos = (pos + 1) % s1.size();
if (++cnt >= s1.size()) {
printf("0\n");
return;
}
}
pos = (pos + 1) % s1.size();
f[i][0] += cnt + 1;
}
}
for (int j = 1; j <= 30; ++j)
for (int i = 0; i < s1.size(); ++i) f[i][j] = f[i][j - 1] + f[(i + f[i][j - 1]) % s1.size()][j - 1];
long long m = 0;
for (int st = 0; st < s1.size(); ++st) {
long long x = st, ans = 0;
for (int k = 30; k >= 0; --k) {
if (x + f[x % s1.size()][k] <= s1.size() * n1) {
x += f[x % s1.size()][k];
ans += 1 << k;
}
}
m = max(m, ans);
}
printf("%lld\n", m / n2);
}
int main() {
while (cin >> s2 >> n2 >> s1 >> n1) dp();
}

浙公网安备 33010602011771号