poj3167 Cow Patterns KMP、树状数组

来源:互联网 发布:luxsens 人工智能 编辑:程序博客网 时间:2024/06/05 19:26
最近的日子被考试压得喘不过气来,说好的每天水两道题又荒废了。。。

为了让写解题报告和看解题报告不那么无聊,我决定从这篇起每篇加几句心得或感慨(很大几率是废话):

数据结构是好东西,必须信手拈来,或者准备好模块,熟练得像std::sort那样,才能克服一些稍显复杂的堆砌算法的题目。
另外,KMP是神奇的算法。

poj3167
KMP&树状数组。

这题要求第一串中间是否有与第二串的匹配的子串。只不过匹配方式改成了只要大小关系相同就算可匹配。

思考后,有个重要的结论:
当某一段s1[i..j]与s2[k..l]可以匹配,那么对于s1[i..j+1]与s2[k..l+1]是否能匹配的充要条件是:
s1[i..j]中小于s1[j+1]的数和s2[k..l]中小于s2[l+1]的数个数相同,等于的个数也相同(那么大于的个数自然也相同)。

有了这个结论,就可以通过修改KMP算法求出匹配串了。

具体就是通过树状数组统计s1[i..j],s2[k..l]中小于和等于的数的个数就可以了。这题的S范围很小,暴力也应该可以。




#include<cstdio>#include<cstring>using namespace std;#define lowbit(x) (x&(-x))#define NN 101000int c1[NN],c2[NN],next[NN],s,ans[NN];char s1[NN],s2[NN];void update(int c[],int x,int val){    while(x<=s){        c[x]+=val;        x+=lowbit(x);    }}int query(int c[],int x){    int ret=0;    while(x){        ret+=c[x];        x-=lowbit(x);    }    return ret;}void getnext(int next[],char s2[],int l2){    int i=0,j=-1;    int tail=1;    memset(c1,0,sizeof(c1));    memset(c2,0,sizeof(c2));    next[i]=j;    while(i<l2){       if ( j<0||            (query(c2,s2[j]-1)==query(c1,s2[i]-1) && query(c2,s2[j])==query(c1,s2[i]))          )       {         if (j>-1) update(c2,s2[j],1);         if (i>0) update(c1,s2[i],1);         i++;j++;next[i]=j;       }       else {         int k=j-1;         j=next[j];         for(k;k>=j;k--) {if (k<0) break;update(c2,s2[k],-1);}         int tt=i-j;         for(tail;tail<tt;tail++) update(c1,s2[tail],-1);       }    }}int KMP(char s1[],char s2[],int l1,int l2,int next[]){    int i,j;    int cnt=0;    int tail=0;    i=j=-1;    memset(c1,0,sizeof(c1));    memset(c2,0,sizeof(c2));    while(i<l1 && j<l2){          if(j<0||             (query(c2,s2[j]-1)==query(c1,s1[i]-1) && query(c2,s2[j])==query(c1,s1[i]))            )          {            if (j>-1) update(c2,s2[j],1);            if (i>-1) update(c1,s1[i],1);            i++;j++;          }          else {            int k=j-1;            j=next[j];            for(k;k>=j;k--) {if (k<0)break;update(c2,s2[k],-1);}            int tt=i-j;            for(tail;tail<tt;tail++) update(c1,s1[tail],-1);          }          if (j>=l2) {              ans[++cnt]=i-j;              int k=j-1;              j=next[j];              for(k;k>=j;k--) {if (k<0)break;update(c2,s2[k],-1);}              int tt=i-j;              for(tail;tail<tt;tail++) update(c1,s1[tail],-1);          }    }    return cnt;}int main(){    //freopen("3167in.txt","r",stdin);    int n,kk,l1,l2,cnt,i,a;    while(scanf("%d%d%d",&n,&kk,&s)!=EOF){        int l1=l2=-1;        for(i=1;i<=n;++i){            l1++;            scanf("%d",&a);            s1[l1]=a;        }        for(i=1;i<=kk;++i){            l2++;            scanf("%d",&a);            s2[l2]=a;        }        s1[++l1]=0;        s2[++l2]=0;        getnext(next,s2,l2);        cnt=KMP(s1,s2,l1,l2,next);        printf("%d\n",cnt);        for(i=1;i<=cnt;++i){            printf("%d\n",ans[i]+1);        }    }    return 0;}





原创粉丝点击