NOIP 考前 KMP练习

Posted on 2016-11-02 14:13  yyjxx2010xyu  阅读(245)  评论(0编辑  收藏  举报

BZOJ 1461 && BZOJ 1729

KMP+BIT

一看就是字符串匹配但是不同的是要按照每个字符的排名情况。

首先对于数字x的排名,那么要判断x前小于x的数的个数,和x前小于等于x的数的个数,这两个都相等才相等。因为会有数字会有重复的.

然后可以先预处理出字串的每个数字的排名,这样就不需要两个BIT了。最后按照KMP的思路做就可以了.

 1 #include <cstdio>
 2 #include <cstring>
 3 const int MaxN=500100;
 4 const int MaxS=10010;
 5 int a[MaxN],b[MaxN],Rk1[MaxN],Rk2[MaxN],Ans[MaxN],tot,n,k,s,P[MaxN];
 6 int c[MaxS];
 7 inline int Lowbit(int x) {return x&-x;}
 8 inline void Add(int x,int d)
 9 {for (int i=x;i<=s;i+=Lowbit(i)) c[i]+=d;}
10 inline int Query(int x)
11 {
12     int Ret=0;
13     for (int i=x;i;i-=Lowbit(i)) Ret+=c[i];
14     return Ret;
15 }
16 int main()
17 {
18     scanf("%d%d%d",&n,&k,&s);
19     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
20     for (int i=1;i<=k;i++)
21     {
22         scanf("%d",&b[i]); Add(b[i],1);
23         Rk1[i]=Query(b[i]),Rk2[i]=Query(b[i]-1);
24     }
25     memset(c,0,sizeof(c)); int j=0;
26     for (int i=2;i<=k;i++)
27     {
28         Add(b[i],1);
29         while (j && ((Query(b[i])!=Rk1[j+1]) || (Query(b[i]-1)!=Rk2[j+1])))
30         {
31             for (int l=i-j;l<i-P[j];l++) Add(b[l],-1);
32             j=P[j];
33         }
34         if ((Query(b[i])==Rk1[j+1]) && (Query(b[i]-1)==Rk2[j+1])) j++;
35         P[i]=j;
36     }
37     memset(c,0,sizeof(c)); j=0;
38     for (int i=1;i<=n;i++)
39     {
40         Add(a[i],1);
41         while (j && (Query(a[i])!=Rk1[j+1] || Query(a[i]-1)!=Rk2[j+1])) 
42         {
43             for (int l=i-j;l<i-P[j];l++) Add(a[l],-1);
44             j=P[j];
45         }
46         if (Query(a[i])==Rk1[j+1] && Query(a[i]-1)==Rk2[j+1]) j++;
47         if (j==k)
48         {
49             Ans[++tot]=i-j+1;
50             for (int l=i-j+1;l<=i-P[j];l++) Add(a[l],-1);
51             j=P[j];
52         }
53     }
54     printf("%d\n",tot);
55     for (int i=1;i<=tot;i++) printf("%d\n",Ans[i]);
56     return 0;
57     
58 }
双倍经验