YBTOJ 2.3KMP 算法

A.子串查找

image
image

板子 详见KMP学习笔记

点击查看代码
#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 0721;
char s1[N], s2[N];
int kmp[N];
int ans;

int main() {
    scanf("%s%s", s1, s2);
    int len1 = strlen(s1);
    int len2 = strlen(s2);
    for (int k = 0, i = 1; i < len2; ++i) {
        while (k && (s2[i] != s2[k])) k = kmp[k];
        if (s2[i] == s2[k])
            kmp[i + 1] = ++k;
        else
            kmp[i + 1] = 0;
    }
    for (int k = 0, i = 0; i < len1; ++i) {
        while (k && (s1[i] != s2[k])) k = kmp[k];
        if (s1[i] == s2[k])
            k++;
        else
            k = 0;
        if (k == len2)
            ++ans;
    }

    // for( int i = 1 ; i <= len2 ; ++i )
    // printf("%d " ,kmp[i] ) ;
    printf("%d", ans);

    return 0;
}

B.重复子串

image
image

看到重复子串 想到最小循环节 进而想到 \(KMP\)
但是对于这题 如果最小循环节不是原串的约数 那么就代表它最后一次出现被砍掉了后面一段 显然是不符合题目条件的 这时候原串自己才是重复子串

点击查看代码
#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 0721;
int nxt[N];

int main() {
	
	string s;
	while (cin >> s) {
		if (s[0] == '.')
			break;
		int len = s.length();
		memset(nxt, 0, sizeof(nxt));
		for (int i = 1, k = 0; i < len; ++i) {
			while (k && s[i] != s[k])
			k = nxt[k];
			
			if (s[i] == s[k])
			nxt[i+1] = ++k;
		
		}
		int cir = len - nxt[len];
		if (len % cir == 0)
			printf("%d\n",len / cir);
		else
			printf("1\n");		
	}
	
	return 0;
}

C.周期长度和

image
image

还是周期问题
并且是最大周期长度 也就是说最小 \(border\)
但是 \(10^6\) 的数据范围 暴力跳 \(fail\) 显然会寄掉
然后我们发现只需要跳到根节点的儿子节点 想到一个类似于路径压缩的东西

点击查看代码
#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int N = 1e6 + 0721;
int nxt[N];
char s[N];
int n;
ll ans;

int main() {
    scanf("%d", &n);
    scanf("%s", s);

    for (int i = 1, j = 0; i < n; ++i) {
        while (j && s[i] != s[j]) j = nxt[j];
        if (s[i] == s[j])
            nxt[i + 1] = ++j;
        else
            nxt[i + 1] = 0;
    }

    for (int i = 1; i <= n; ++i) {
        int j = i;
        while (nxt[j] != 0) j = nxt[j];
        if (nxt[i] != 0)
            nxt[i] = j;
        ans += i - j;
    }

    printf("%lld", ans);

    return 0;
}

D.子串拆分

image
image

看到类似于 \(A + B + A\) 的形式 想到跳不重复 \(border\)
然后发现这题 \(O(n^2)\) 就能过 直接对每个子串暴力做 \(KMP\) 即可
代码咕了

posted @ 2023-06-28 16:44  Steven24  阅读(58)  评论(0编辑  收藏  举报