题目链接:http://codeforces.com/contest/631/problem/D
题意:
给你两个个块集组成的字符串,字符串中每一块有这个字母的数量和这个字母,第一个是父亲字符串,第二个是儿子字符串,问你儿子字符串和父亲匹配次数的有多少。
做法:
和普通的KMP又有点不一样,这里加上了一个数字,在正式匹配之前,当然要先去重,保证每一块和前后都不一样。然后做kmp的时候,不管是求next数组,还是正常的匹配,都要带上一个数量的数组,在数组两边也相同的时候再作处理。这里还有一个小技巧,如果子字符串的块为1或者2就直接做处理,不然先精确的做中间的kmp,把有效的头保存下来,(因为第一块和最后一块的要求只是字母相同的情况下数量不大于父亲的就可以了,但是中间是必须一模一样,所以精确做的时候取中间的就好了)。然后再看看前后是否搭配上即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=200505;
const int mod=(int)1e9+7;
typedef long long ll;
ll numfa[maxn],numson[maxn],numtmp[maxn];
char aimfa[maxn],aimson[maxn],aimtmp[maxn];
int nex[maxn],n,m;
vector<int> preans;
//KMP匹配得到的next由子串
void kmp_next(char *str2,ll *num,int *next,int len){
int i,j;
next[1] = 0;
j = 0;
for(int i=2;i<=len;i++){
while(j>0&&(str2[j+1]!=str2[i]||num[j+1]!=num[i]))
j=next[j];
if(str2[j+1]==str2[i]&&num[j+1]==num[i])
j++;
next[i]=j;
}
}
int kmp_re(char *str1,ll *num1,char *str2,ll *num2,int *next,int len1,int len2){
int j=0;
for(int i=1;i<=len1;i++){
while(j>0&&(str2[j+1]!=str1[i]||num2[j+1]!=num1[i]))
j=next[j];
if(str2[j+1]==str1[i]&&num2[j+1]==num1[i])
j++;
if(j==len2){
preans.push_back(i-len2);
j=next[j];
}
}
}
char s[10];
int main(){
ll ans=0,c;
scanf("%d%d",&n,&m);
int gen=0,gem=0;
for(int i=0;i<n;i++){
scanf("%lld-%s",&c,s+1);
if(s[1]==aimfa[gen]){
numfa[gen]+=c;
}
else{
gen++;
numfa[gen]=c;
aimfa[gen]=s[1];
}
}
for(int i=0;i<m;i++){
scanf("%lld-%s",&c,s+1);
if(s[1]==aimson[gem]){
numson[gem]+=c;
}
else{
gem++;
numson[gem]=c;
aimson[gem]=s[1];
}
}
n=gen;
m=gem;
if(m==1){
for(int i=1;i<=n;i++){
if(aimfa[i]==aimson[1]){
ans=(ans+max(0ll,numfa[i]-numson[1]+1));
}
}
}
else if(m==2){
for(int i=1;i<n;i++){
if(aimson[1]==aimfa[i]&&aimson[2]==aimfa[i+1]&&numson[1]<=numfa[i]&&numson[2]<=numfa[i+1]){
ans++;
}
}
}
else{
for(int i=2;i<m;i++){
aimtmp[i-1]=aimson[i];
numtmp[i-1]=numson[i];
}
kmp_next(aimtmp,numtmp,nex,m-2);
kmp_re(aimfa,numfa,aimtmp,numtmp,nex,n,m-2);
for(int i=0;i<preans.size();i++){
int l=preans[i],r=l+m-1;
if(aimfa[l]==aimson[1]&&aimfa[r]==aimson[m]&&numfa[l]>=numson[1]&&numfa[r]>=numson[m])
ans++;
}
}
printf("%lld\n",ans);
return 0;
}