链接
Codeforces 631D Messenger
题意
a-b表示有a个字符b。 用这样的表示方式给出主串和模式串,问模式串在主串中出现了多少次。
思路
非常明显的KMP了,这里只要匹配去掉两端的模式串,端点单独匹配就好了。
代码
#include <bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
#define eps 1e-8
#define MAXN 200005
using namespace std;
struct node{
LL num;
char ch;
node(LL x = 0, char y = 0) :num(x), ch(y){};
bool operator <= (const node &b)const{
return ch == b.ch && num <= b.num;
}
bool operator == (const node &b)const{
return ch == b.ch && num == b.num;
}
};
node a[MAXN], b[MAXN];
int last[MAXN];
int res[MAXN];
void work(char *s, LL &x, char &ch){
x = 0;
int p = 0;
while (s[p] != '-'){
x = x * 10 + s[p] - '0';
++p;
}
ch = s[p + 1];
}
int n, m;
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
scanf("%d%d", &n, &m);
int p = 0;
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
char s[30];
LL x;
char ch;
for (int i = 1; i <= n; ++i){
scanf("%s", s);
work(s, x, ch);
if (p == 0 || ch != a[p].ch){
a[++p] = node(x, ch);
}
else{
a[p].num += x;
}
}
n = p;
p = 0;
for (int i = 1; i <= m; ++i){
scanf("%s", s);
work(s, x, ch);
if (p == 0 || ch != b[p].ch){
b[++p] = node(x, ch);
}
else{
b[p].num += x;
}
}
m = p;
last[2] = 1;
x = 1;
for (int i = 3; i <= m - 1; ++i){
while (b[x + 1].ch != b[i].ch && x > 1){
x = last[x];
}
if (b[x + 1].ch == b[i].ch){
++x;
}
last[i] = x;
}
LL ans = 0;
if (m > 2){
x = 1;
int cnt = 0;
for (int i = 2; i < n; ++i){
while (x > 1 && (!(a[i] == b[x + 1]))){
x = last[x];
}
if (a[i] == b[x + 1]){
++x;
}
if (x == m - 1){
if (b[1] <= a[i - m + 2] && b[m] <= a[i + 1]){
++ans;
}
x = last[x];
}
}
}
if (m <= 2){
for (int i = 1; i <= n; ++i){
if (b[1] <= a[i] && b[m] <= a[i + m - 1]){
if (m == 1){
ans += a[i].num - b[1].num + 1;
}
else{
++ans;
}
}
}
}
printf("%I64d\n", ans);
}