jzoj4624NOIP2016A组模拟7.13KMP数学字符串匹配

Posted SSL_ZZL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jzoj4624NOIP2016A组模拟7.13KMP数学字符串匹配相关的知识,希望对你有一定的参考价值。


题面

Description

在这里插入图片描述

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

2
usaco
cowusacousa

Sample Output

3

Data Constraint

在这里插入图片描述


解题思路

在这里插入图片描述

一切的一切都因为一个%lld(((((((

易想, 做一段的KMP,求出一段的答案,然后用数学求出复制出n段的KMP
做一遍KMP(求出答案为A)
首尾相连会产生出更多的答案
将字符串倍长一遍,再做一个KMP(求出答案为A + B + A)
(A为单个段的答案,B为首尾合并产生的答案)
那么答案为((A + B) * n - B) (- B是因为最后复制的一段,后面没有连接的首尾,也就没有B)


Code

#include <iostream>
#include <cstring>
#include <cstdio>
#define ll unsigned long long
#define maxn 100100

using namespace std;

ll ans1, ans2, twice, once;
ll n, p[maxn * 2];
char a[maxn * 2], b[maxn];

void work1() {  //第一遍KMP,求出A
	ll lenb = strlen(b + 1), lena = strlen(a + 1);
	for(int i = 1, j = 0; i < lenb; i++) {
		while(j > 0 && b[j + 1] != b[i + 1])
			j = p[j];
		if(b[j + 1] == b[i + 1]) j++;
		p[i + 1] = j;
	}
	for(int i = 0, j = 0; i < lena; i++) {
		while(j > 0 && b[j + 1] != a[i + 1])
			j = p[j];
		if(b[j + 1] == a[i + 1]) j++;
		if(j == lenb)
			ans1++, j = p[j];
	}
}

void work2() {  //第二遍KMP,求出A + B + A
	ll lenb = strlen(b + 1), lena = strlen(a + 1);
	for(int i = 1, j = lena + 1; i <= lena; i++, j++)
		a[j] = a[i];
	lena = strlen(a + 1);
	for(int i = 0, j = 0; i < lena; i++) {
		while(j > 0 && b[j + 1] != a[i + 1])
			j = p[j];
		if(b[j + 1] == a[i + 1]) j++;
		if(j == lenb)
			ans2++, j = p[j];
	}
}

int main() {
	scanf("%lld", &n);
	scanf("%s", b + 1);
	scanf("%s", a + 1);
	work1();
	work2();
	twice = ans2 - ans1;  //twice = (A + B + A) - A = A + B
	once = twice * 2 - ans2;  //once = (A + B) * 2 - (A + B + A) = B
	printf("%lld", twice * n - once);  //(A + B) * 2 - B
}

以上是关于jzoj4624NOIP2016A组模拟7.13KMP数学字符串匹配的主要内容,如果未能解决你的问题,请参考以下文章

Jzoj4742NOIP2016提高A组模拟9.2快速幂单峰

jzoj3508NOIP2013模拟11.5B组DAY 1 (7.12)HASH好元素(good)

jzoj3510NOIP2013模拟11.5B组DAY 1 (7.12)DP最短路径(path)

jzoj6276. noip提高组模拟1树

jzoj3505NOIP2013模拟11.4A组组合逆元积木

jzoj3515NOIP2013模拟11.6B组二分DP软件公司