// // // // // // // // // // // // // //

关于 KMP

KMP 算法

1. 剪花布条

/*
  Time: 1.10
  Worker: Blank_space
  Source: #10043. 「一本通 2.2 例 1」剪花布条
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<iostream>
#define emm(x) memset(x, 0, sizeof x)
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int p[1010], ans;
char s[1010], c[1010];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/

/*----------------------------------------函数*/
int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);

    while(1)
    {
    	cin >> s + 1;
    	if(s[1] == '#' && !s[2]) return 0;
    	cin >> c + 1; emm(p); ans = 0;
    	int m = strlen(s + 1), n = strlen(c + 1);
    	for(int i = 1, j = 0; i <= n; i++)
    	{
    		while(c[i + 1] != c[j + 1] && j) j = p[j];
    		p[i + 1] = c[i + 1] == c[j + 1] ? ++j : j;
    	}
    	for(int i = 0, j = 0; i < m; i++)
    	{
    		while(s[i + 1] != c[j + 1] && j) j = p[j];
    		j += (s[i + 1] == c[j + 1]);
    		if(j == n) ans++, j = 0;
    	}
    	printf("%d\n", ans);
    }
    
//  fclose(stdin);
//  fclose(stdout);
	return 0;
}

2. Power Strings

/*
  Time: 1.10
  Worker: Blank_space
  Source: #10044 「一本通 2.2 例 2」Power Strings
  题目重了 这个题在字符串哈希那里做过... 
  
  用哈希对每一个串的判断同样可以优化到 O(1)
  但感觉这个 kmp 的思路确实很神 
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int p[C];
char s[C];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/

/*----------------------------------------函数*/
int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);

    while(1)
    {
    	scanf("%s", s + 1);
    	if(s[1] == '.') return 0;
    	int n = strlen(s + 1); p[1] = 0;
    	for(int i = 1, j = 0; i <= n; i++)
    	{
    		while(s[i + 1] != s[j + 1] && j) j = p[j];
    		p[i + 1] = s[i + 1] == s[j + 1] ? ++j : 0;
    	}
    	if(!(n % (n - p[n]))) printf("%d\n", n / (n - p[n]));
    	else puts("1");
    }
    
//  fclose(stdin);
//  fclose(stdout);
	return 0;
}

3. Radio Transmission

/*
  Time: 1.10
  Worker: Blank_space
  Source: #10045. 「一本通 2.2 练习 1」Radio Transmission
  结论题: ans = n - p[n]
  p[n] 是 n 找到的上一个位置 可以理解为将 整个串向前移动 使得 n 位置与 p[n] 位置对应
  不难看出移动前的串中从 1 至 p[n] 一定是由移动后的 1 的位置到移动前的 1 的位置构成的 例如:
       1234 1234 1234 12
  1234 1234 1234 12
  所以 答案即为最大的公共前缀(后缀) 
*/
/*--------------------------------------------*/
#include<cstdio>
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int n, p[C];
char s[C];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/

/*----------------------------------------函数*/
int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);

    n = read(); scanf("%s", s + 1);
    for(int i = 1, j = 0; i <= n; i++)
    {
    	while(s[i + 1] != s[j + 1] && j) j = p[j];
    	p[i + 1] = s[i + 1] == s[j + 1] ? ++j : 0;
    }
    printf("%d", n - p[n]);
    
//  fclose(stdin);
//  fclose(stdout);
	return 0;
}

4. OKR-Periods of Words

/*
  Time: 1.13
  Worker: Blank_space
  Source: #10046. 「一本通 2.2 练习 2」OKR-Periods of Words
  把题目翻译成人话:
  求 给定字符串的所有子串除却其最小非空前缀 的长度和 
*/
/*--------------------------------------------*/
#include<cstdio>
using namespace std; 
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
long long n, p[C], ans;
char s[C];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/

/*----------------------------------------函数*/
int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);

    n = read(); scanf("%s", s + 1);
    for(int i = 1, j = 0; i <= n; i++)
    {
    	while(s[i + 1] != s[j + 1] && j) j = p[j];
    	p[i + 1] = s[i + 1] == s[j + 1] ? ++j : 0;
    }
    for(int i = 1, j = 1; i <= n; i++, j = i)
    {
    	while(p[j]) j = p[j];
    	if(p[i]) p[i] = j;
    	ans += i - j;
    }
    printf("%lld", ans);
    
//  fclose(stdin);
//  fclose(stdout);
	return 0;
}

5. 似乎在梦中见过的样子

/*
  Time: 1.9
  Worker: Blank_space
  Source: #10047. 「一本通 2.2 练习 3」似乎在梦中见过的样子
*/
/*---------------------------------------------------*/
#include<cstdio>
#include<cstring>
using namespace std;
/*---------------------------------------------------*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*---------------------------------------------------*/
long long k, p[B], ans, f[B];
char s[B];
/*---------------------------------------------------*/
int read()
{
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*---------------------------------------------------*/
void kmp(char *s)
{
	for(int i = 2, j = 0; s[i]; i++)
	{
		while(s[i] != s[j + 1] && j) j = p[j];
		p[i] = s[i] == s[j + 1] ? ++j : 0;
	}
	for(int i = 1, j = 0; s[i]; i++)
	{
		while(s[i] != s[j + 1] && j) j = p[j];
		j += s[i] == s[j + 1];
		while(j << 1 >= i) j = p[j];
		ans += j >= k;
	}
}
/*---------------------------------------------------*/
int main()
{
//	freopen("", "r", stdin);
//	freopen("", "w", stdout);
	
	scanf("%s", s + 1); k = read();
	for(int i = 0; s[i + 1]; i++) kmp(s + i);
	printf("%lld", ans);
	
//	fclose(stdin);
//	fclose(stdout);
}


gugugu~

posted @ 2021-01-30 14:02  Blank_space  阅读(43)  评论(0编辑  收藏  举报
// // // // // // //