我们定义代表S的第i块,代表T的第i块。
同时代表S的l到r位,并且,代表T的l到r位。
若T是S的字串,则S[l + 1..r - 1]=T[2..m - 1]且S[l].l = T[1].l且S[l].c ≥ T[1].c且S[r].l = T[m].l且S[r].c ≥ T[m].c.
所以我们只需要找到在S 中出现的地方,然后再检查一下边界,这可以用KMP算法解决。
另外:
-
和的情况可以特殊处理
-
若相邻的两块所含的字符相同,则可以合并
-
答案需要储存在long long中
Time:
Memory:
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
struct dat{
ll l;
char c;
friend bool operator<=(const dat &d1,const dat &d2)
{
return (d1.c==d2.c) && (d1.l<=d2.l);
}
friend bool operator==(const dat &d1,const dat &d2)
{
return (d1.c==d2.c) && (d1.l==d2.l);
}
}a[200001],b[200001];
int f[200001],n,m;
void cp(dat *a,int &n)
{
int m=0;
for(int i=0;i<n;++i)
{
if(m==0 || a[m-1].c!=a[i].c)
a[m++]=a[i];
else
a[m-1].l+=a[i].l;
}
n=m;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;++i)scanf("%lld-%c",&a[i].l,&a[i].c);
for(int i=0;i<m;++i)scanf("%lld-%c",&b[i].l,&b[i].c);
cp(a,n);
cp(b,m);
ll ans=0;
switch(m) {
case 1:{
for(int i=0;i<n;++i)
if (b[0]<=a[i])
ans+=a[i].l-b[0].l+1;
break;
}
case 2:{
for(int i=0;i<n-1;++i)
if (b[0]<=a[i]&&b[1]<=a[i + 1])
++ans;
break;
}
default:{
f[1]=0;
for(int i=2;i<m-1;i++) {
int j=f[i-1];
while(j>0&&!(b[j+1]==b[i]))
j=f[j];
if (b[j+1]==b[i])
j++;
f[i]=j;
}
for(int i=1,j=0;i<n-1;i++){
while (j>0 && !(b[j+1]==a[i]))
j=f[j];
if(b[j+1]==a[i])
j++;
if(j==m-2)
{
if(b[0]<=a[i-j] && b[j+1]<=a[i+1])
ans++;
j=f[j];
}
}
}
}
printf("%lld\n",ans);
}