通过此题掌握到了一个新知识 : 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 T≤100, ∑ n ≤ ∑ m ≤ 1 0 3 \sum n\leq \sum m\leq 10^3 ∑n≤∑m≤103。字符串仅由大小或者小写的英文字母组成。
输入格式
输入共 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]abcabca
,abc[abc]abca
,abcabc[abc]a
;
对于第二组输入,出现了
9
9
9 次,分别是 [Aa]AaaAaAa
,A[aA]aaAaAa
,Aa[Aa]aAaAa
,AaA[aa]AaAa
,AaAa[aA]aAa
,AaAaa[Aa]Aa
,AaAaaA[aA]a
,AaAaaA[aA]a
,AaAaaAa[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;
}