Codeforces 631D - Messenger KMP

来源:互联网 发布:装修手机设计软件 编辑:程序博客网 时间:2024/06/05 20:15

题目:http://codeforces.com/problemset/problem/631/D
题意:
输入一段压缩后的字符串,问子串在主串中出现的次数
分析:
KMP匹配求子串在主串中出现的次数,因为是压缩后的字符串,这就要考虑字符串的长度。因为要完全匹配,显然,模式串的中间的字符和数目必须要完全和主串匹配,但是前后两个字符数目可以不相等,所以模式串删去前后两个字符,去和主串匹配,完全匹配时,在比较前后两个字符是否主串中相应位置的字符匹配。删去前后两个字符前,要判断模式串长度:
如果模式串长度是1,那么直接在主串中找对应的字符,比较长度,如果模式串长度是2,那么也是直接在主串中找模式串,比较字符一样,并且主串中字符数目均不小于模式串中字符数目。然后剩下的就用KMP匹配就好。

#include<iostream>#include<cstdio>using namespace std;#define fi first#define se second#define mp make_pairtypedef long long ll;typedef pair<char,ll>pii;const int N=2e5+5;pii s[N],t[N],t0,tt;int next[N],tlen,slen;void getNext(){    int i,j;    i=0;j=next[0]=-1;    while(i<tlen){        if(j==-1||t[i]==t[j])next[++i]=++j;        else j=next[j];    }}ll KMP_Count(){    ll ans=0;    getNext();    int j=0;    for(int i=1;i<slen;i++){        while(j>0&&s[i]!=t[j])j=next[j];        if(s[i]==t[j])j++;        if(j==tlen){            if(t0.fi==s[i-tlen].fi&&t0.se<=s[i-tlen].se            &&tt.fi==s[i+1].fi&&tt.se<=s[i+1].se)ans++;            j=next[j];        }    }    return ans;}int main(){    int n,m;    //freopen("f.txt","r",stdin);    scanf("%d%d",&n,&m);    char ci;    ll li;    scanf("%I64d-%c",&s[0].se,&s[0].fi);    n--; slen=1;    while(n--){        scanf("%I64d-%c",&li,&ci);        if(s[slen-1].fi==ci){            s[slen-1].se+=li;        }        else s[slen++]=mp(ci,li);    }    scanf("%I64d-%c",&t[0].se,&t[0].fi);    //cout<<t[0].fi<<' '<<t[0].se<<endl;    m--; tlen=1;    while(m--){        scanf("%I64d-%c",&li,&ci);        if(t[tlen-1].fi==ci){            t[tlen-1].se+=li;        }        else t[tlen++]=mp(ci,li);    }    if(tlen==1){        ll ans=0;        for(int i=0;i<slen;i++){            if(t[0].fi==s[i].fi&&t[0].se<=s[i].se)ans+=s[i].se-t[0].se+1;        }        cout<<ans<<endl;return 0;    }    if(tlen==2){        ll ans=0;        for(int i=1;i<slen;i++){            if(t[0].fi==s[i-1].fi&&t[1].fi==s[i].fi               &&t[0].se<=s[i-1].se&&t[1].se<=s[i].se){                ans++;            }        }        cout<<ans<<endl;return 0;    }    t0=t[0];tt=t[tlen-1];    for(int i=0;i<tlen-1;i++)        t[i]=t[i+1];    tlen-=2;    cout<<KMP_Count()<<endl;    return 0;}

Input

The first line of the input contains two integers n and m (1 ≤ n, m ≤ 200 000) — the number of blocks in the strings t and s, respectively.

The second line contains the descriptions of n parts of string t in the format “li-ci” (1 ≤ li ≤ 1 000 000) — the length of the i-th part and the corresponding lowercase English letter.

The second line contains the descriptions of m parts of string s in the format “li-ci” (1 ≤ li ≤ 1 000 000) — the length of the i-th part and the corresponding lowercase English letter.
Output

Print a single integer — the number of occurrences of s in t.
Examples
Input

5 3
3-a 2-b 4-c 3-a 2-c
2-a 2-b 1-c

Output

1

0 0