Description&Data Constraint
Will相信,很多同学都有过这样的经历:大牛已经写好了编程作业,而作为菜鸟的自己不会写怎么办呢?拿大牛的代码抄一下嘛!但是提交一模一样的作业是不是不太好?于是就改一改变量名什么的……但是其实这样的代码抄袭行为是可以被检测出来的。
考虑到如下的两段代码,很容易发现他们其实是一样的。
那么最开始给出的两段雷同代码就可以分别写成 AiBjCiDECjDiFGC 以及 AaBiCaDECiDaFGC。或者简单的说,我们认为这两段代码是一样的。
现在请写一个程序,处理若干这样的代码雷同检测问题:给一个完整代码以及一个较短的代码片段,请求出,这个代码片段在完整代码中一共出现了多少次(代码片段出现的位置可以重叠)。
为了简单起见,我们认为程序中只会至多出现 (a)~(z) 这26个变量,同时也至多只有 (A) ~ (Z) 这26个非变量符号。
对于100%的数据满足 (Qle3),(|T|le100000),(|S|le1000000)。
Solution
这题就是一个很明显的KMP,但是关键在于对小写字母的处理。
其实可以发现,小写字母是什么并不重要,重要的是他们之间的位置。而大写字母要保持一致。
因此可以对于每个小写字母,那个位置变成他与上一个同样的字母之间的距离,如果这个距离是一样的,那么就是可以匹配的。
但是这并不是所有。
举个例子,完整代码: (aababa),代码片段:(cdcd)。
根据上述的转换可以变成 (010222) 和 (0022)。发现如果仅仅在这上面跑 KMP 是会遗漏答案的。
因为对于位置 4 的 (a) 来说,在完整的代码中它距离上一个为 2,但是如果在完整片段中从第 3 个开始匹配,第 4 个 (a) 就变成了第一个,就可以与代码片段匹配。
所以对于当前匹配的区间中,如果一个字母是第一次出现,那么它可以跟任何一个数字匹配,前提是在当前区间中它是第一个。
Code
#include<cstdio>
#include<cstring>
#define N 1000005
using namespace std;
int T,n,m,ans,match[N<<1],t[30],a[N],b[N],s[N<<1];
char ch;
void init1()
{
memset(t,-1,sizeof(t));
while (!((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))) ch=getchar();
while (((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')))
{
if (ch>='a'&&ch<='z')
{
t[ch-'a'+1]==-1?a[n]=0:a[n]=n-t[ch-'a'+1];
t[ch-'a'+1]=n;
++n;
}
else a[n++]=-(ch-'A'+1);
ch=getchar();
}
}
void init2()
{
memset(t,-1,sizeof(t));
while (!((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))) ch=getchar();
while (((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')))
{
if (ch>='a'&&ch<='z')
{
t[ch-'a'+1]==-1?b[m]=0:b[m]=m-t[ch-'a'+1];
t[ch-'a'+1]=m;
++m;
}
else b[m++]=-(ch-'A'+1);
ch=getchar();
}
}
bool check(int x,int y,int len)
{
if (x<0||y<0) return x==y;
return x==y||(y==0&&x>len);
}
int main()
{
scanf("%d",&T);
while (T--)
{
n=m=ans=0;
memset(match,0,sizeof(match));
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
init1();init2();
for (int i=0;i<m;++i)
s[i]=b[i];
s[m]=100;
for (int i=0;i<n;++i)
s[m+i+1]=a[i];
for (int i=1;i<=n+m;++i)
{
int j=match[i-1];
while (j>0&&!check(s[i],s[j],j)) j=match[j-1];
if (check(s[i],s[j],j)) ++j;
match[i]=j;
}
for (int i=m+1;i<=n+m;++i)
if (match[i]==m) ++ans;
printf("%d
",ans);
}
return 0;
}