P8835 [传智杯 #3 决赛] 子串 -- (kmp求解 / transform函数应用)

通过此题掌握到了一个新知识 : transform函数的应用

点击此处跳转题目:P8835 [传智杯 #3 决赛] 子串


[传智杯 #3 决赛] 子串

题目背景

disangan233 喜欢字符串,于是 disangan333 想让你找一些 disangan233 喜欢的串。

题目描述

在传智的开发课堂上,希望您开发一款文档处理软件。

给定 T T T 组询问,每次给定 2 2 2 个长度为 n , m n,m n,m 的只含英文字母的字符串 a , b a,b a,b,求 a a a b b b 中的出现次数,相同字符不区分大小写。注意 a a a b b b 中连续子序列。

对于所有数据, T ≤ 100 T\leq 100 T100 ∑ n ≤ ∑ m ≤ 1 0 3 \sum n\leq \sum m\leq 10^3 nm103。字符串仅由大小或者小写的英文字母组成。

输入格式

输入共 3 T + 1 3T+1 3T+1 行。

1 1 1 行输入 1 1 1 个正整数 T T T

接下来共 T T T 组输入,每组输入共 3 3 3 行。

1 1 1 行输入 2 2 2 个正整数 n , m n,m n,m

2 2 2 行输入一个长度为 n n n 的字符串 a a a

3 3 3 行输入一个长度为 m m m 的字符串 b b b

输出格式

输出共 T T T 行,第 i i i 行输出 1 1 1 个整数,表示询问 i i i 的答案。

样例 #1

样例输入 #1

5
3 10
abc
abcabcabca
2 10
aa
AAaAaaAaAa
5 5
AbCdE
eDcBa
5 5
abcde
ABCDE
3 10
aba
ABaBaAbaBA

样例输出 #1

3
9
0
1
4

提示

对于第一组输入,出现了 3 3 3 次,分别是 [abc]abcabcaabc[abc]abcaabcabc[abc]a

对于第二组输入,出现了 9 9 9 次,分别是 [Aa]AaaAaAaA[aA]aaAaAaAa[Aa]aAaAaAaA[aa]AaAaAaAa[aA]aAaAaAaa[Aa]AaAaAaaA[aA]aAaAaaA[aA]aAaAaaAa[Aa]


解析:

这里我直接放上代码:kmp有不理解的可以看我另外一篇博客很详细:
KMP深入刨析


在这里引入一段对transform函数的简单讲解:
transform函数可以一次性将字符串转换。
transform函数有两个重载版本:
transform(first,last,result,op);
//first是容器的首迭代器,last为容器的末迭代器,result为存放结果的容器,op为要进行操作的一元函数对象或sturct、class。

transform(first1,last1,first2,result,binary_op);
//first1是第一个容器的首迭代器,last1为第一个容器的末迭代器,first2为第二个容器的首迭代器,result为存放结果的容器,binary_op为要进行操作的二元函数对象或sturct、class。

1.transform函数的使用

transform在指定的范围内应用于给定的操作,并将结果存储在指定的另一个范围内。transform函数包含在头文件中。

以下是std::transform的两个声明,

一元操作:

template <class InputIterator, class OutputIterator, class UnaryOperation>

OutputIterator transform (InputIterator first1, InputIterator last1,OutputIterator result, UnaryOperation op);
对于一元操作,将op应用于[first1, last1]范围内的每个元素,并将每个操作返回的值存储在以result开头的范围内。给定的op将被连续调用last1-first1+1次。

op可以是函数指针或函数对象或lambda表达式。

例如:op的一个实现 即将[first1, last1]范围内的每个元素加5,然后依次存储到result中。

int op_increase(int i) {return (i + 5)};
调用std::transform的方式如下:

std::transform(first1, last1, result, op_increase);
二元操作:

template <class InputIterator1, class InputIterator2,class OutputIterator, class BinaryOperation>
OutputIterator transform (InputIterator1 first1, InputIterator1 last1,InputIterator2 first2, OutputIterator result,BinaryOperation binary_op);

对于二元操作,使用[first1, last1]范围内的每个元素作为第一个参数调用binary_op,并以first2开头的范围内的每个元素作为第二个参数调用binary_op,每次调用返回的值都存储在以result开头的范围内。给定的binary_op将被连续调用last1-first1+1次。binary_op可以是函数指针或函数对象或lambda表达式。

例如:binary_op的一个实现即将first1和first2开头的范围内的每个元素相加,然后依次存储到result中。

int op_add(int, a, int b) {return (a + b)};
调用std::transform的方式如下:

std::transform(first1, last1, first2, result, op_add);

举例:

#include <bits/stdc++.h>
using namespace std;

int main(int argc, char** argv) {
	string s="HELLO";
	transform(s.begin(),s.end(),s.begin(),::tolower);
	cout<<s<<endl;//输出hello
	
	string s2="hello";
	transform(s2.begin(),s2.end(),s2.begin(),::toupper);
	cout<<s2;//输出HELLO
	return 0;
}


完整代码:

#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
const int N = 1e3 + 10;
int ne[N];
string a,b;	
int n,m;	//a,b串的长度 
//transform的搭配函数 
char op(char ch)
{
	if(ch >= 'A' && ch <= 'Z')
		return ch + 32;
	else 
		return ch;
}

void getNext() {
	int k = -1,j = 0;
	ne[0] = -1;
	while(j < n) {
		if(k == -1 || a[k] == a[j]) {
			ne[++j] = ++k;
		} else {
			k = ne[k];
		}
	}
}

int kmp() {
	int r,i,j;
	r = i = j = 0;
	while(i < m) {
		if(j == -1 || a[j] == b[i]) {
			i++;
			j++;
		} else {
			j = ne[j];
		}
		//数量的判断
		if(j == n) {
			r++; 
			j = ne[j];
		}
	}
	return r;
}
int main()
{
	int T;
	cin >> T;
	while(T--) {
		memset(ne,0,sizeof(ne));
		cin >> n >> m;
		cin >> a >> b;
		transform(a.begin(),a.end(),a.begin(),op);
		transform(b.begin(),b.end(),b.begin(),op);
		 
		getNext();
		int res = kmp();
		
		cout << res << endl;
				
	}
		
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值