计算重复题解

计算重复(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();
}
posted @ 2025-02-10 15:47  hnczy  阅读(46)  评论(0)    收藏  举报