1. 程式人生 > >BZOJ1729: [Usaco2005 dec]Cow Patterns 牛的模式匹配

BZOJ1729: [Usaco2005 dec]Cow Patterns 牛的模式匹配

space ems ace img 數字出現次數 stdlib.h 表示 計算 scan

n<=1e5個數字,給m<=25000個數字做模板串,給的數字都<=25,求n個數中有多少個子串滿足這樣的與模板串匹配:長度與模板串相同,且子串中第一、二、三、……個數字在該子串中的排名和模板串中第一、二、三、……個數字在模板串中的排名相同,如:1 4 4 2和4 6 6 5匹配。

兩串匹配--KMP。但這個題的匹配模式不同於傳統的匹配模式。有點難的題,但有助於更好的理解KMP的原理。

回顧下KMP整個過程:模板串做失配函數,然後模板串中開個指針利用失配函數和原串匹配。也就是,如果我們知道“匹配”應滿足什麽條件,就可以完成所有的工作。

兩串匹配,滿足條件:一:這兩串的上一串,即當前考慮的字符去掉,本來就已經匹配了;二:當前考慮的字符加入後仍滿足匹配。也就是說,只要能找到一個滿足條件二的計算方式就可以做了。在此題中,這個條件二可表示為:兩串分別新加進來這個數字的排名相等,而數字很小,這個排名可以迅速計算。

錯誤!條件考慮不周。原來兩串:1 2 3 5和2 3 4 5,現在串一加數字4,串二加數字5,排名相同,但是不能匹配的。究其原因,這裏的“排名”不僅指小排名,而且指大排名,就是比他小的、比他大的數量都一樣。但實際上不必這樣,因為總數-小排名-大排名=這個數字出現次數,總數肯定是一樣的,所以只要小排名和這個數字出現次數一樣即可。

技術分享
 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 #include<stdlib.h>
 5 //#include<math.h>
6 //#include<iostream> 7 using namespace std; 8 9 int n,m,T; 10 #define maxn 100011 11 int a[maxn],sa[maxn][30],b[maxn],sb[maxn][30],fail[maxn]; 12 bool equal(int* s1,int sa[][30],int x,int* s2,int sb[][30],int y) 13 { 14 int x1=0,x2=0,y1=0,y2=0; 15 for (int i=0;i<s1[x];i++) x1+=sa[x][i]-sa[x-y][i];
16 for (int i=0;i<s2[y];i++) y1+=sb[y][i]; 17 x2=sa[x][s1[x]]-sa[x-y][s1[x]],y2=sb[y][s2[y]]; 18 return (x1==y1 && x2==y2); 19 } 20 void makef() 21 { 22 fail[1]=fail[2]=1; 23 for (int i=2;i<=m;i++) 24 { 25 int j=fail[i]; 26 while (j>1 && !equal(b,sb,i,b,sb,j)) j=fail[j]; 27 fail[i+1]=equal(b,sb,i,b,sb,j)?j+1:1; 28 } 29 } 30 int ans[maxn],lans=0; 31 int main() 32 { 33 scanf("%d%d%d",&n,&m,&T); 34 memset(sa[0],0,sizeof(sa[0])); 35 for (int i=1;i<=n;i++) 36 { 37 scanf("%d",&a[i]); 38 for (int j=0;j<26;j++) sa[i][j]=sa[i-1][j]; 39 sa[i][a[i]]++; 40 } 41 memset(sb[0],0,sizeof(sb[0])); 42 for (int i=1;i<=m;i++) 43 { 44 scanf("%d",&b[i]); 45 for (int j=0;j<26;j++) sb[i][j]=sb[i-1][j]; 46 sb[i][b[i]]++; 47 } 48 makef(); 49 int j=1; 50 for (int i=1;i<=n;i++) 51 { 52 while (j>1 && !equal(a,sa,i,b,sb,j)) j=fail[j]; 53 if (equal(a,sa,i,b,sb,j)) j++; 54 if (j>m) 55 { 56 ans[++lans]=i-m+1; 57 j=fail[j]; 58 } 59 } 60 printf("%d\n",lans); 61 for (int i=1;i<=lans;i++) printf("%d\n",ans[i]); 62 return 0; 63 }
View Code

BZOJ1729: [Usaco2005 dec]Cow Patterns 牛的模式匹配