CF 631D KMP/Z

Posted Live In A Dream

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF 631D KMP/Z相关的知识,希望对你有一定的参考价值。

给定两个压缩形式的字符串,如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】的数量。

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

技术分享
  1 #include <iostream>
  2 #include <vector>
  3 #include <algorithm>
  4 #include <string>
  5 #include <string.h>
  6 #include <stdio.h>
  7 #include <math.h>
  8 #include <stdlib.h>
  9 #include <queue>
 10 #include <stack>
 11 #include <map>
 12 #include <set>
 13 #include <ctime>
 14 #include <numeric>
 15 #include <cassert>
 16 
 17 using namespace std;
 18 
 19 const int N=1e6+100;
 20 
 21 
 22 struct Char {
 23     char ch;
 24     long long cnt;
 25     bool operator == (const Char &o) const {
 26         return ch==o.ch&&cnt==o.cnt;
 27     }
 28 };
 29 int z[N];
 30 Char f[N];
 31 void Z(int n) {
 32     z[0]=n;
 33     int L=0,R=0;
 34     for (int i=1;i<n;i++) {
 35         if (i>R) {
 36             L=i,R=i;
 37             while (R<n&&f[R-i]==f[R]) R++;
 38             z[i]=R-L;
 39             R--;
 40         }
 41         else {
 42             int k=i-L;
 43             if (z[k]<R-i+1)
 44                 z[i]=z[k];
 45             else {
 46                 L=i;
 47                 while (R<n&&f[R-i]==f[R]) R++;
 48                 z[i]=R-L;
 49                 R--;
 50             }
 51         }
 52     }
 53 }
 54 Char s[N],t[N];
 55 
 56 
 57 int main() {
 58     int n,m;
 59     scanf("%d %d",&n,&m);
 60     char buf[5];
 61     for (int i=0;i<n;i++) {
 62         long long cnt;
 63         scanf("%I64d-%s",&cnt,buf);
 64         t[i].cnt=cnt;
 65         t[i].ch=buf[0];
 66     }
 67     int k=1;
 68     for (int i=1;i<n;i++) {
 69         if (t[i].ch==t[i-1].ch)
 70             t[k-1].cnt+=t[i].cnt;
 71         else {
 72             t[k++]=t[i];
 73         }
 74     }
 75     n=k;
 76     for (int i=0;i<m;i++) {
 77         long long cnt;
 78         scanf("%I64d-%s",&cnt,buf);
 79         s[i].cnt=cnt;
 80         s[i].ch=buf[0];
 81     }
 82     k=1;
 83     for (int i=1;i<m;i++) {
 84         if (s[i].ch==s[i-1].ch)
 85             s[k-1].cnt+=s[i].cnt;
 86         else {
 87             s[k++]=s[i];
 88         }
 89     }
 90     m=k;
 91 
 92     if (m==1) {
 93         long long ret=0;
 94         for (int i=0;i<n;i++) {
 95             if (t[i].ch==s[0].ch&&t[i].cnt>=s[0].cnt) {
 96                 ret+=t[i].cnt-s[0].cnt+1;
 97             }
 98         }
 99         printf("%I64d\n",ret);
100         return 0;
101     }
102     int len=0;
103     for (int i=1;i<m;i++) {
104         f[len++]=s[i];
105     }
106     f[len].ch=#;
107     f[len].cnt=0;
108     len++;
109     int from=len;
110     for (int i=0;i<n;i++) {
111         f[len++]=t[i];
112     }
113     Z(len);
114     int ret=0;
115     for (int i=from+1;i<len;i++) {
116         int lcp=z[i];
117         if (t[i-from-1].ch==s[0].ch&&t[i-from-1].cnt>=s[0].cnt) {
118             if (lcp==m-1)
119                 ret++;
120             else if (lcp==m-2) {
121                 if (s[m-1].ch==t[i-from+lcp].ch&&s[m-1].cnt<=t[i-from+lcp].cnt)
122                     ret++;
123             }
124         }
125     }
126     printf("%d\n",ret);
127     return 0;
128 }
View Code

 

以上是关于CF 631D KMP/Z的主要内容,如果未能解决你的问题,请参考以下文章

631D Messenger

扩展KMP(Z函数),线性LCP

如何从后台弹出片段

cf 模拟

CF1435 游记

无法解析符号 c882c94be45fff9d16a1cf845fc16ec5