631D Messenger
题目大意
给你串s和t
但是每个串都被表示为多个二元组(x,y)表示字符x连续出现y次
问t在s中出现了多少次
分析
我们先将s和t每个串中二元组合并
即相邻两个二元组如果字符相等则将它们变为一个
特判掉m=1的情况
其余情况我们发现对于相等位置除了t的开头结尾两个二元组
其余二元组一定与和s的对应位置完全一样
我们把t去掉头尾放在前面
然后将s放在后面
求出它们的z函数
之后对于s的每个位置如果它的z[i]大于等于m-2
且它的两端字符和t两端相等且个数不小于
那么这个位置合法
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define int long long
char l[500100],ls[500100],lt[500100];
int c[500100],cs[500100],ct[500100],n,m,z[500100],ans,N;
inline void get_z(){
int i,j,k,le=0,ri=0;
z[0]=N;
for(i=1;i<N;i++){
if(i<=ri)z[i]=min(ri-i+1,z[i-le]);
while(z[i]+i<N&&l[z[i]]==l[z[i]+i]&&c[z[i]]==c[z[i]+i])z[i]++;
if(z[i]+i-1>ri)ri=z[i]+i-1,le=i;
}
}
signed main(){
int i,j,k;
scanf("%lld%lld",&n,&m);
for(i=0;i<n;i++)scanf("%lld-%c",&cs[i],&ls[i]);
N=0;
for(i=1;i<n;i++)
if(ls[i]==ls[i-1])cs[N]+=cs[i];
else ls[++N]=ls[i],cs[N]=cs[i];
n=N+1;
for(i=0;i<m;i++)scanf("%lld-%c",&ct[i],<[i]);
N=0;
for(i=1;i<m;i++)
if(lt[i]==lt[i-1])ct[N]+=ct[i];
else lt[++N]=lt[i],ct[N]=ct[i];
m=N+1;
if(m==1){
for(i=0;i<n;i++)
if(ls[i]==lt[0]&&cs[i]>=ct[0])ans+=cs[i]-ct[0]+1;
printf("%lld\n",ans);
return 0;
}
N=n+m-2;
for(i=1;i<m-1;i++)l[i-1]=lt[i],c[i-1]=ct[i];
for(i=0;i<n;i++)l[m-2+i]=ls[i],c[m-2+i]=cs[i];
get_z();
for(i=m-1;i<N-m+2;i++)
if(z[i]>=m-2&&l[i-1]==lt[0]&&l[i+m-2]==lt[m-1]&&c[i-1]>=ct[0]&&c[i+m-2]>=ct[m-1])ans++;
printf("%lld\n",ans);
return 0;
}