33 ACwing 294 Count The Repetitions 题解

Count The Repetitions

题面

定义 conn(s,n) 为 n 个字符串 s 首尾相接形成的字符串,例如:

conn(“abc”,2)=”abcabc”

称字符串 a 能由字符串 b 生成,当且仅当 a 为 b 的子序列。

例如 abdbec 可以生成 abc,但是 acbbe 不能生成 abc

给定两个字符串 s1 和 s2,以及两个整数 n1 和 n2,求一个最大的整数 m,满足 conn(conn(s2,n2),m) 能由 conn(s1,n1) 生成。

s1 和 s2 长度不超过 100,n1 和 n2 不大于 \(10 ^ 6\)

题解

我们可以转化一下,实际上就是要求一个最大的 \(m'\) 使得 \(conn(s_2, m_2)\) 能由 \(conn(s_1,n_1)\) 生成

暴力枚举的话,就是将 \(conn (s_1,n_1)\) 枚举一遍,能匹配上就匹配,时间复杂度为 \(O(T|s_1|n_1)\)

\(m'\) 可能很大,上界为 \(|s_1|n_1/|s_2|\) ,考虑将 \(m'\) 进行二进制拆分,那么我们可以将 \(conn(s_2,m')\) 看做若干个 \(conn(s_2,2^x)\) 相连的形式

我们可以求出 \(k \in [0,\log_2(|s_1|n1 / |s_2|)]\) ,从 \(conn(s_1,n_1)\) 的每个位置开始最少多长的字符串能拼出 \(2^k\)\(s_2\)

但是 \(n_1\) 也非常大,不过因为 \(conn(s_1,n_1)\) 是由 \(s_1\) 重复 \(n_1\) 次得到的,所以只要没有到结尾,从 \(s_1[i]\) 开始和从 \(s_1[i + k|s_1|]\) 开始往后的字符是一样的,所以我们可以假设 \(n_1\) 无限大,然后只计算 \(i \le |s_1|\) 的从 \(s_1[i]\) 开始的位置即可

\(f(i,j)\) 表示从 \(s_1[i]\) 开始匹配到 \(2^j\)\(s_1\) 最短需要多少个字符,我们只需预处理出 \(f(i,0)\) 即可,后面的可以递推得出

预处理 \(f(i,0)\) 暴力匹配即可,时间复杂度为 \(O(100^3)\)

code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>

using namespace std;

typedef long long ll;

const int N = 110;

int n1, n2;
char s1[N], s2[N];
ll f[N][32];


void solve () {
    int sz = strlen (s1);
    //预处理 f[i][0]
    for (int i = 0; i < sz; i ++) {
        f[i][0] = 0;
        int p = i;
        for (int j = 0; j < (int)strlen (s2); j ++) {
            int cnt = 0;
            while (s1[p] != s2[j]) {
                p = (p + 1) % sz;
                cnt ++;
                if (cnt >= sz) {
                    cout << 0 << endl;
                    return;
                }
            }
            p = (p + 1) % sz;
            f[i][0] += cnt + 1;
        }
    }
    //计算出 f[i][j]
    for (int j = 1; j <= 30; j ++) {
        for (int i = 0; i < sz; i ++) {
            f[i][j] = f[i][j - 1] + f[(i + f[i][j - 1]) % sz][j - 1];
        }
    }

    //计算答案
    ll res = 0, p = 0, t = 0;
    for (int j = 30; j >= 0; j --) {
        if (p + f[p % sz][j] <= n1 * sz) {
            p += f[p % sz][j];
            t += (1 << j);
        }
    }
    res = max (res, t);
    cout << res / n2 << endl;
}

int main () {
    while (~scanf ("%s%d%s%d", s2, &n2, s1, &n1)) {
        solve ();
    }

    return 0;
}
posted @ 2025-10-05 18:14  michaele  阅读(5)  评论(0)    收藏  举报