题意:
给出两个分别为n,m项的字符串
求第二个字符串在第一个中出现几次
字符串按照 (li,ci) ( l i , c i ) 的形式给出
(如2-a 2-b 1-c 表示aabbc)
n,m<=2e5 l<=1e6 n , m <= 2 e 5 l <= 1 e 6
Solution:
直接匹配比较困难
观察发现去掉模式串的首尾两端 中间的串和文本串是完全匹配的,对于完全匹配问题,我们使用双关键字KMP/双关键词x-box即可
最后对于每个匹配位置判断一下头尾即可
注意需要合并连续的相等的c,特判m=1
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int mod=1315326179;
int z[400010],n,m,r,l,p,x;
long long b[200010],a[200010],num[400010];
char s1[200010],s2[200010],S[400010];
int wei;
int ans=0;
char s[5];
char pre=0;
int fast_pow(int a,int x)
{
int ans=1;
for (;x;x>>=1,a=1ll*a*a%mod)
if (x&1) ans=1ll*ans*a%mod;
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
scanf("%s",s);
//cout<<s<<" "<<x<<endl;
if (s[1]==pre) i--,n--,a[i]+=x;
else a[i]=x,s2[i]=s[1];
pre=s[1];
}
pre='1';
for (int i=1;i<=m;i++)
{
scanf("%d",&x);
scanf("%s",s);
if (s[1]==pre) i--,m--,b[i]+=x;
else b[i]=x,s1[i]=s[1];
pre=s[1];
}
if (m==1)
{
long long ans=0;
for (int i=1;i<=n;i++)
if (s2[i]==s1[1]&&a[i]>=b[1]) ans+=a[i]-b[1]+1;
printf("%lld",ans);
return 0;
}
for (int i=2;i<m;i++)
S[i-2]=s1[i],num[i-2]=b[i];
for (int i=1;i<=n;i++)
S[m+i-2]=s2[i],num[i+m-2]=a[i];
// for (int i=0;i<=m+n-2;i++)
// {
// printf("%c %d\n",S[i],num[i]);
// }
for (int i=1;i<=m+n-2;i++)
{
if (i>r)
{
int t=i,bg=0;
while (S[t]==S[bg]&&num[t]==num[bg])
t++,bg++;
z[i]=bg;
r=t-1;
l=i;
}
else
{
if (z[i-l]<r-i+1) z[i]=z[i-l];
else
{
int t=r+1,bg=r-i+1;
while (S[t]==S[bg]&&num[t]==num[bg])
t++,bg++;
z[i]=bg;
r=t-1;
l=i;
}
}
}
for (int i=m-1;i<=m+n-2;i++)
if (z[i]==m-2)
if (S[i-1]==s1[1]&&num[i-1]>=b[1]&&S[i+m-2]==s1[m]&&num[i+m-2]>=b[m]) ans++;
printf("%d",ans);
}