【codevs3945】 完美拓印

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
",ans);
    return 0;
}

  

原文地址:https://www.cnblogs.com/MashiroSky/p/6077877.html