题目大意:
给你两个数组 a,b。还有一个间隔长度 t 。现在让你找 a 数组以长度 t 为间隔,里面有多少个 b 。
分析:
以 t 为间隔将 a 数组分成几个子序列,然后每个子序列分别与 b 进行匹配,用 kmp 。
后经测试发现,这道题直接暴力枚举也是可以过的。两个方法的代码都贴一下吧。
代码:
暴力枚举:608ms
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
using namespace std;
#define maxn 1000500
int n,m,t;
int a[maxn],b[maxn];
int main()
{
int T;
int test=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&t);
test++;
int s=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=m;i++)//b作为模式串去和他们匹配
{
scanf("%d",&b[i]);
}
int end=n-t*(m-1);
for(int i=1;i<=end;i++)
{
int flag=1;
for(int j=1;j<=m;j++)
{
if(b[j]!=a[i+(j-1)*t])
{
flag=0;
break;
}
}
if(flag==1)s++;
}
printf("Case #%d: %d\n",test,s);
}
}
KMP匹配优化:608ms 真的没骗你,我可能是用了假的kmp~
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
using namespace std;
#define maxn 1000500
int n,m,t;
int a[maxn],b[maxn];
int Next[maxn];
int c[maxn];//按间隔提取出的a的子序列
void get_Next()
{
Next[0]=-1;
int k=-1,i=0;
while(i<m)
{
if(k!=-1&&b[i]!=b[k])
{
k=Next[k];
continue;
}
k++;i++;
if(i==m)
{
Next[i]=k;
break;
}
if(b[i]!=b[k])Next[i]=k;
else Next[i]=Next[k];
}
}
int match(int numc)
{
int s=0;
int i=0,j=0;
while(1)
{
if(i>=numc&&j<m)break;
if(j==m||c[i]!=b[j])
{
if(j==m)s++;
j=Next[j];
if(j==-1)
{
j++;i++;
}
continue;
}
i++;j++;
}
return s;
}
int main()
{
int T;
int test=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&t);
test++;
int s=0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
for(int i=0;i<m;i++)//b作为模式串去和他们匹配
{
scanf("%d",&b[i]);
}
/*int end=n-t*(m-1);
for(int i=1;i<=end;i++)
{
int flag=1;
for(int j=1;j<=m;j++)
{
if(b[j]!=a[i+(j-1)*t])
{
flag=0;
break;
}
}
if(flag==1)s++;
}*/
get_Next();
for(int i=0;i<t;i++)
{
int numc=0;//c数组元素个数
int j=i;
while(1)
{
c[numc]=a[j];
numc++;
j+=t;
if(j>=n)break;
}
if(numc>=m)s+=match(numc);
//cout<<numc<<endl;
}
printf("Case #%d: %d\n",test,s);
}
}