题目大意:给你一个神奇的印章,他左右下三个面都是直的,上面是凸凹不平的面(凸凹都平行于别的面)。然后给你一个轮廓线,如果一个面能与轮廓线完全重合,可以把印章的这个沿着轮廓线拓印,求所有的拓印方案。
把轮廓线和印章相邻两个高度打个查分,然后KMP匹配一下就行了。
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <vector> 5 #define N 10010 6 #define mod 1000000007 7 #define ui unsigned int 8 #define ll long long 9 #define dd double 10 #define idx(x) x-'a'+1 11 using namespace std; 12 //re 13 int T,n,m,cnt; 14 int nxt[3][N]; 15 ui f[N]; 16 int a[N],b[N],s[N],t[3][N]; 17 void get_kmp(int s1[],int p) 18 { 19 int i=1,j=0; 20 nxt[p][1]=0; 21 while(i<m) 22 { 23 if(j==0||s1[i]==s1[j]) 24 { 25 i++; 26 j++; 27 nxt[p][i]=j; 28 }else{ 29 j=nxt[p][j]; 30 } 31 } 32 } 33 int KMP(int s1[],int s2[],int p) 34 { 35 int i=1,j=1,cnt=0; 36 while(i<n) 37 { 38 if(j==0||s1[i]==s2[j]) 39 { 40 i++; 41 j++; 42 }else{ 43 j=nxt[p][j]; 44 } 45 if(j==m) 46 { 47 cnt++; 48 j=nxt[p][j]; 49 } 50 } 51 return cnt; 52 } 53 54 55 int main() 56 { 57 scanf("%d%d",&m,&n); 58 for(int i=1;i<=m;i++) scanf("%d",&b[i]); 59 for(int j=1;j<=n;j++) scanf("%d",&a[j]); 60 if(m==1) {printf("%d\n",n*4);return 0;} 61 for(int i=1;i<m;i++) t[0][i]=b[i+1]-b[i],t[2][i]=0; 62 for(int i=1;i<m;i++) t[1][i]=t[0][m-i]; 63 for(int i=1;i<n;i++) s[i]=a[i+1]-a[i]; 64 get_kmp(t[0],0),get_kmp(t[1],1),get_kmp(t[2],2); 65 int ans=0; 66 ans+=KMP(s,t[0],0); 67 ans+=KMP(s,t[1],1); 68 ans+=2*KMP(s,t[2],2); 69 printf("%d\n",ans); 70 return 0; 71 } 72 73 74