题目描述
一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?
输入
输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样。花纹条和小饰条不会超过1000个字符长。如果遇见#字符,则不再进行工作。
输出
输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出0,每个结果之间应换行。
样例输入
abcde a3
aaaaaa aa
#
样例输出
0
3
题解
最近学习了KMP字符串算法,心血来潮写一篇博客……
虽说exKMP要比KMP难一些,但是由于给我讲算法的师姐只给我讲了exKMP,所以我只会exKMP(因为老师还没有正式讲QwQ),貌似KMP可以解决的问题exKMP都能解决,而exKMP能解决的问题KMP不一定能解决QwQ,所以我就贴exKMP的算法啦~
好了,那么什么是exKMP呢?
exKMP问题就是求出模式串A与被匹配字符串
例如A=aab B=aabaaab
B的后缀起始下标 | 与A的最长公共前缀长度 | |
---|---|---|
aabaaab | 3 | |
abaaab | 1 | |
baaab | 0 | |
aaab | 2 | |
aab | 3 | |
ab | 1 | |
b |
exKMP看似需要O(n2)的时间,但是和KMP问题一样,exKMP问题也可以在O(n)的时间内做出来。我们定义两个数组:
nex:A的所有后缀与
ex:B的所有后缀与
我们先看看怎么求出辅助数组nex
显然,nex[0]=lena,nex[1]可以O(n)暴力求出
然后我们考虑在知道了nex[1...i−1]后求出nex[i]。
由nex的定义得,nex[j]表示从第j位开始,有连续的
我们在[1,i)中找到一个p最大的
所以就分成了两种情况:
- 如果i+nex[i−j]<maxp,那么nex[i]=nex[i−j]。
- 如果i+nex[i−j]>=maxp呢?很遗憾,你只能从maxp开始暴力做(当然别忘了更新j和
maxp )……但是不要沮丧,每一个位置只会被暴力做一次(做完后就被maxp覆盖了),所以时间依然是O(n)!
至此,我们求出了nex数组,那怎么求ex数组呢?我们可以用类似的步骤重做一次,只需要注意几个细节就基本算是copy了……
附上求nex代码片
nex[0]=n;//特殊情况
for(int i=1;i<n;i++)
if(A[i]==A[i-1])nex[1]++;
else break;//暴力
maxp=nex[1]+1;po=1;//不说话
for(int i=2;i<n;i++)
{
if(i+nex[i-po]<maxp)nex[i]=nex[i-po];//第一种情况
else nex[i]=max(maxp-i,0);
while(i+nex[i]<n&&A[nex[i]]==A[i+nex[i]])nex[i]++;//第二种情况开始暴力……
if(i+nex[i]>maxp)maxp=i+nex[i],po=i;
}
好了我们回到原题,通过exKMP,我们能够求出ex数组,如果ex[i]=n说明i号位置的后缀可以与模式串匹配,那么就可以剪下
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1000005
char A[N],B[N];//A为模式串 B为匹配串
int nex[N],ex[N],maxp,po,n,m;
void exKMP(char *A,char *B)
{
memset(nex,0,sizeof(nex));
memset(ex,0,sizeof(ex));
n=strlen(A);m=strlen(B);
nex[0]=n;
for(int i=1;i<n;i++)
if(A[i]==A[i-1])nex[1]++;
else break;
maxp=nex[1]+1;po=1;
for(int i=2;i<n;i++)
{
if(i+nex[i-po]<maxp)nex[i]=nex[i-po];
else nex[i]=max(maxp-i,0);
while(i+nex[i]<n&&A[nex[i]]==A[i+nex[i]])nex[i]++;
if(i+nex[i]>maxp)maxp=i+nex[i],po=i;
}
for(int i=0;i<n;i++)
if(A[i]==B[i])ex[0]++;
else break;
maxp=ex[0];po=0;
for(int i=1;i<m;i++)
{
if(i+nex[i-po]<maxp)ex[i]=nex[i-po];
else ex[i]=max(maxp-i,0);
while(ex[i]<n&&i+ex[i]<m&&A[ex[i]]==B[i+ex[i]])ex[i]++;
if(i+ex[i]>maxp)maxp=i+ex[i],po=i;
}
}
int main()
{
for(;;)
{
scanf("%s",B);
if(B[0]=='#')
break;
scanf("%s",A);
exKMP(A,B);
int last=0,sum=0;
for(int i=0;i<m;i++)
if(ex[i]==n&&i>=last)
sum++,last=i+n;
printf("%d\n",sum);
}
}