【codevs3945】 完美拓印

时间:2021-12-28 21:42:35

http://codevs.cn/problem/3945/ (题目链接)

题意

  给出一个诡异的图形,再给出一个歪七扭八的线,问图形上下两条边与线的匹配→_→

Solution

  前后求差然后KMP,这种数字的匹配还是KMP靠谱,hash太容易冲突了。

细节

  注意可以上下翻转有4种匹配方式

代码

// codevs3945
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#define LL long long
#define inf 2147483640
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=1000010;
int next[maxn],t[maxn],p[maxn],a[maxn],b[maxn];
int n,m; void calnext() {
next[1]=0;
for (int i=2,j=0;i<=n;i++) {
while (j && p[j+1]!=p[i]) j=next[j];
if (p[j+1]==p[i]) j++;
next[i]=j;
}
}
int kmp() {
calnext();
int cnt=0;
for (int j=0,i=1;i<=m;i++) {
while (j && t[i]!=p[j+1]) j=next[j];
if (t[i]==p[j+1]) j++;
if (j==n) cnt++,j=next[j];
}
return cnt;
}
int main() {
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int j=1;j<=m;j++) scanf("%d",&b[j]);
if (n==1) {printf("%d",m*4);return 0;}
n--,m--;int ans=0;
for (int i=1;i<=n;i++) p[i]=a[i+1]-a[i];
for (int i=1;i<=m;i++) t[i]=b[i+1]-b[i];
ans+=kmp();
for (int i=1;i<=n;i++) p[i]=a[n-i+2]-a[n-i+1];
ans+=kmp();
for (int i=1;i<=n;i++) p[i]=0;
ans+=2*kmp();
printf("%d\n",ans);
return 0;
}