其他分享
首页 > 其他分享> > cf314 B. Sereja and Periods

cf314 B. Sereja and Periods

作者:互联网

题意:

定义 \(str^k\) 表示字符串 \(str\) 重复 \(k\) 次。

给定 \({s_1}^{k_1}\) 和 \(s_2^{k_2}\),求最大的整数 \(ans\) 使得 \((s_2^{k_2})^{ans}\) 是 \(s_1^{k_1}\) 的子序列

\(1\le |s_1|,|s_2|\le 100, 1\le k_1,k_2\le 1e7\)

思路:

有种比较直接的思路是模拟匹配的过程,每次在 \(s_1^{k_1}\) 上找一段 \([l,r]\) 来匹配一个 \(s_2\) 串,即 \(s_1^{k_1}\) 包含 \(s_2\)

预处理 \(nxt_i\) 表示从 \(s_1\) 的第 \(i\) 个位置开始匹配一个完整的 \(s_2\),最终会在 \(s_1\) 的哪个位置停下。这个过程可能会经过多个 \(s_1\) 串,用 \(cnt_i\) 表示经过的 \(s_1\) 串的末尾的数量

之后就是模拟整个匹配过程,初始指针 \(p\) 指向 \(s_1^{k_1}\) 串首,每次在 \(s_1^{k_1}\) 里从 \(p\) 开始匹配一个 \(s_2\),答案加上 \(cnt_p\),\(p\) 向右移动到 \(nxt_p\)

上述过程一直重复,直到 \(p\) 移动到 \(s_1^{k_1}\) 之外。复杂度为 \(p\) 的移动次数

然而最坏情况下,\(p\) 每次仅右移 1,需要移动 \(1e9\) 次,会超时!

稍微改变一下思路,每次取一个 \(s_1\),看这个 \(s_1\) 能包含多少 \(s_2\)

预处理 \(nxt_i\) 表示从 \(s_2\) 的第 \(i\) 个位置开始匹配,用一个完整的 \(s_1\) 能让 \(i\) 右移到 \(s_2\) 的哪个位置。用 \(cnt_i\) 表示经过的 \(s_2\) 串的末尾的数量

初始指针 \(p\) 指向 \(s_2\) 串首,每次答案加上 \(cnt_p\),\(p\) 向右移动到 \(nxt_p\)

上述过程每次取一个 \(s_1\),一共只有 \(k_1\) 个 \(s_1\),复杂度 \(O(k_1)\)

最后答案除以 \(k_2\) 再下取整即可

const signed N = 3 + 100;
int k1, k2, nxt[N], cnt[N]; char s1[N], s2[N];
void sol() {
    cin >> k1 >> k2 >> (s1 + 1) >> (s2 + 1);
    int n1 = strlen(s1 + 1), n2 = strlen(s2 + 1);

    for(int i = 1; i <= n2; i++) { //预处理
        nxt[i] = i;
        for(int j = 1; j <= n1; j++) if(s2[nxt[i]] == s1[j])
            if(++nxt[i] > n2) nxt[i] = 1, cnt[i]++;
    }

    int p = 1, ans = 0;
    while(k1--) ans += cnt[p], p = nxt[p];
    cout << ans/k2;
}

标签:nxt,cnt,le,匹配,int,Sereja,cf314,Periods,ans
来源: https://www.cnblogs.com/wushansinger/p/16368764.html