【poj 3167】Cow Patterns(字符串--KMP匹配+数据结构--树状数组)
题意:给2个数字序列 a 和 b ,问按从小到达排序后,a中的哪些子串与b的名次匹配。 a 的长度 N≤100,000,b的长度 M≤25,000,数字的大小 K≤25。
解法:【思考】1.X 暴力。枚举 a 中的子串,选出来排序后比对名次。O(n* m log m *m)=O(n*m^2*log m)。
2.X 暴力+树状数组优化。枚举 a 中的子串,选出来后比较前缀名次(P.S.这种转化常出现,比如:【洛谷 p3368】模板-树状数组 2(数据结构) 就是将个体转化为前缀。),看加上自己的之前小于等于和等于该数的个数是否相等。O(n*m log m)。
3.√ kmp+树状数组优化。直接kmp匹配 a串和 b串,next[ ]预处理 b串,再在kmp时看前缀名次来比较。(这个要kmp理解得很好才能在处理树状数组时处理得很好,我现在思绪混乱啊......代码就算了......qwq)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 7 const int N=100010,M=25010,K=30; 8 struct node{int x,y,d;}b[M],a[N]; 9 int a[N],b[M],next[M]; 10 int cnt=0,s[N]; 11 int ca[K],cb[K]; 12 13 int lowbit(int x) {return x&-x;} 14 int change(int x,int d) 15 { 16 for (int i=x;i<=n;i+=lowbit(i)) 17 ca[i]+=d; 18 } 19 int getcount(int x) 20 { 21 int sum=0; 22 for (int i=x;i>=1;i-=lowbit(i)) 23 sum+=ca[i]; 24 return sum; 25 } 26 int change_2(int x,int d) 27 { 28 for (int i=x;i<=m;i+=lowbit(i)) 29 cb[i]+=d; 30 } 31 int getcount_2(int x) 32 { 33 int sum=0; 34 for (int i=x;i>=1;i-=lowbit(i)) 35 sum+=cb[i]; 36 return sum; 37 } 38 void init_kmp() 39 { 40 memset(cb,0,sizeof(cb)); 41 memset(next,0,sizeof(next)); 42 int p=0,x=0,y=0; 43 next[1]=0; 44 for (int i=2;i<=m;i++) 45 { 46 while ((b[i].x!=b[p+1].x||b[i].y!=b[p+1].y) && p) 47 { 48 p=next[p]; 49 } 50 if (b[i].x==b[p+1].x&&b[i].y==b[p+1].y) 51 { 52 p++; 53 add_2(b[i].d,1); 54 } 55 next[i]=p; 56 } 57 } 58 void kmp() 59 { 60 int p=0; 61 for (int i=1;i<=n;i++) 62 { 63 int x=getcount_2(a[i].d-1); 64 while ((a[i].x-(a[i-p].x+a[i-p].y)!=b[p+1].x||a[i].y!=b[p+1].y) && p) p=next[p]; 65 if (a[i].x==b[p+1].x&&a[i].y==b[p+1].y) p++; 66 if (p==m) s[++cnt]=i; 67 } 68 } 69 int main() 70 { 71 freopen("a.in","r",stdin); 72 int n,m,k; 73 scanf("%d%d%d",&n,&m,&k); 74 //memset(ca,0,sizeof(ca)); 75 for (int i=1;i<=n;i++) 76 { 77 scanf("%d",&a[i].d); 78 /*change(a[i].d,1); 79 a[i].x=getcount(a[i].d); 80 a[i].y=a[i].x-getcount(a[i].d-1);*/ 81 } 82 //memset(cb,0,sizeof(cb)); 83 for (int i=1;i<=m;i++) 84 { 85 scanf("%d",&b[i].d); 86 /*change_2(b[i].d,1); 87 b[i].x=getcount_2(b[i].d); 88 b[i].y=b[i].x-getcount_2(b[i].d-1);*/ 89 } 90 init_kmp(); 91 kmp(); 92 printf("%d\n",cnt); 93 for (int i=1;i<=cnt;i++) 94 printf("%d ",s[i]); 95 return 0; 96 }