Codeforces 631D - Messenger KMP

题目: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_pair
typedef 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

posted @ 2016-03-20 13:55  HARD_UNDERSTAND  阅读(158)  评论(0编辑  收藏  举报