Codeforces Round #344 (Div. 2) D. Messenger (kmp)

题目

http://codeforces.com/contest/631/problem/D

题意

给你一个压缩的主串和一个压缩的模式串,压缩方式为分块压缩,相同且相邻的字母压缩到一个块里,用x-c表示(x表示个数,c表示字母)。问模式串在主串中出现了多少次。

思路

和普通的kmp差不多,把每个x-c当成一个字母,再用kmp进行匹配。
和普通字符串的匹配不同的是:如果模式串两边的块要比主串相对应的串少的话也是可以的,这个时候字母个数并不相等,所以这种情况要先把两边的块去掉,先匹配中间的,再判断两边的是不是也能匹配上。
当n等于1和等于2的时候分别特判,n=1的时候,直接暴力扫一遍看出现了几次就行,n=2的时候相同,不过和n=1不同的地方是它和主串匹配的位置是唯一的。
注意:有可能给的字符串两个相邻的是相同字母,所以匹配之前先将相同的合并。

代码

#define push_back pb
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<cmath>
#include<map>
#include<algorithm>
#include<string>
#include<string.h>
#include<set>
#include<queue>
#include<stack>
#include<functional>
typedef long long ll;
using std::pair;
typedef pair<ll,char>pii;
typedef unsigned long long ull;
const double PI=acos(-1);
const int maxn=200000+10;
const int maxm=100000+10;
const int INF = 0x3f3f3f3f;
using namespace std;
int next[maxn];
pii s[maxn],t[maxn],t0,tt;
ll lens,lent;
int n,m;
void getnext()
{
    next[0]=-1;
    int j=0,k=-1;
    while(j<lent)
    {
        if(k==-1||t[j]==t[k])next[++j]=++k;
        else k=next[k];
    }
}

int kmp_count()
{
    int i=0,j=0;
    ll ans=0;
    getnext();
    while(i<lens)
    {
        if(j==-1||s[i]==t[j]) i++,j++;
        else
        {
            if(j==lent)
            {
                if(t0.second==s[i-lent-1].second&&tt.second==s[i].second)
                {
                    if(t0.first<=s[i-lent-1].first&&tt.first<=s[i].first)
                        ans++;
                }

            }
             j=next[j];
        }
    }
    return ans;
}
int main()
{
    cin>>n>>m;
    ll num;
    char c;
    char pre='0';
    lens=lent=-1;
    for(int i=0;i<n;i++)
    {
        scanf("%I64d-%c",&num,&c);
        if(c==pre)
        {
            s[lens].first+=num;
        }
        else
        {
            s[++lens].first=num;
            s[lens].second=c;
        }
        pre=c;
    }
    pre='0';
    lens++;
    for(int i=0;i<m;i++)
    {
        scanf("%I64d-%c",&num,&c);
        if(c==pre)
        {
            t[lent].first+=num;
        }
        else
        {
            t[++lent].first=num;
            t[lent].second=c;
        }
        pre=c;
    }
    lent++;
    if(lent==1)
    {
        ll ans=0;
        for(int i=0;i<lens;i++)
        {
            if(s[i].second==t[0].second)
            {
                ans+=max(0ll,s[i].first-t[0].first+1);
            }
        }
        cout<<ans<<endl;
    }
    else if(lent==2)
    {
        ll ans=0;
        if(lens==1)
            ans=0;
        else
        for(int i=0;i<lens-1;i++)
        {
            if(s[i].second==t[0].second&&s[i+1].second==t[1].second)
            {
                if(s[i].first>=t[0].first&&s[i+1].first>=t[1].first)
                    ans++;
            }
        }
        cout<<ans<<endl;
    }
    else
    {
        t0=t[0],tt=t[lent-1];
        for(int i=0;i<lent-2;i++)
            t[i]=t[i+1];
        lent-=2;
        cout<<kmp_count()<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/a670531899/article/details/81542718
今日推荐