CF #344 D. Messenger KMP/Z

时间:2022-10-31 03:11:45

题目链接:http://codeforces.com/problemset/problem/631/D

给定两个压缩形式的字符串,如a3b5a4k7这样的形式

问A在B中出现次数。

分类讨论,如果A是只有一种字符的,则答案数量可能很大,但计算也很简单,直接看B的每一个字符,答案累加上cnt2-cnt1+1

如果A不是单字符的,则答案至多是B的压缩之后长度的数量级。

不考虑A的第一个字符,用KMP或者Z函数来计算A的出现情况,如果匹配长度为lenA-1,则检查是否该匹配的第一个字符与A【0】相等且数量大于A【0】的数量,如果匹配长度为lenA-2,则检查是否下一个字符与A最后一个字符是相等的,且数量大于A【lenA-1】的数量。

写的时候需要仔细,因为涉及到不少下标以及条件判断。

 #include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctime>
#include <numeric>
#include <cassert> using namespace std; const int N=1e6+; struct Char {
char ch;
long long cnt;
bool operator == (const Char &o) const {
return ch==o.ch&&cnt==o.cnt;
}
};
int z[N];
Char f[N];
void Z(int n) {
z[]=n;
int L=,R=;
for (int i=;i<n;i++) {
if (i>R) {
L=i,R=i;
while (R<n&&f[R-i]==f[R]) R++;
z[i]=R-L;
R--;
}
else {
int k=i-L;
if (z[k]<R-i+)
z[i]=z[k];
else {
L=i;
while (R<n&&f[R-i]==f[R]) R++;
z[i]=R-L;
R--;
}
}
}
}
Char s[N],t[N]; int main() {
int n,m;
scanf("%d %d",&n,&m);
char buf[];
for (int i=;i<n;i++) {
long long cnt;
scanf("%I64d-%s",&cnt,buf);
t[i].cnt=cnt;
t[i].ch=buf[];
}
int k=;
for (int i=;i<n;i++) {
if (t[i].ch==t[i-].ch)
t[k-].cnt+=t[i].cnt;
else {
t[k++]=t[i];
}
}
n=k;
for (int i=;i<m;i++) {
long long cnt;
scanf("%I64d-%s",&cnt,buf);
s[i].cnt=cnt;
s[i].ch=buf[];
}
k=;
for (int i=;i<m;i++) {
if (s[i].ch==s[i-].ch)
s[k-].cnt+=s[i].cnt;
else {
s[k++]=s[i];
}
}
m=k; if (m==) {
long long ret=;
for (int i=;i<n;i++) {
if (t[i].ch==s[].ch&&t[i].cnt>=s[].cnt) {
ret+=t[i].cnt-s[].cnt+;
}
}
printf("%I64d\n",ret);
return ;
}
int len=;
for (int i=;i<m;i++) {
f[len++]=s[i];
}
f[len].ch='#';
f[len].cnt=;
len++;
int from=len;
for (int i=;i<n;i++) {
f[len++]=t[i];
}
Z(len);
int ret=;
for (int i=from+;i<len;i++) {
int lcp=z[i];
if (t[i-from-].ch==s[].ch&&t[i-from-].cnt>=s[].cnt) {
if (lcp==m-)
ret++;
else if (lcp==m-) {
if (s[m-].ch==t[i-from+lcp].ch&&s[m-].cnt<=t[i-from+lcp].cnt)
ret++;
}
}
}
printf("%d\n",ret);
return ;
}