hdu3336 &&hdu 4552 KMP ,SAM

来源:互联网 发布:淘宝中年女模特叫什么 编辑:程序博客网 时间:2024/06/04 19:27

      给一个串,求所有前缀在母串中出现的次数和。

      还是利用失配函数来做,构造完失配函数,然后从末尾向前枚举,对于每个点,如果没有被访问过的话,就沿其失配路径走一遍,并且每经过一个未访问过节点,迭代层数+1(初始为0),若经过的是已经访问的节点,那么迭代层数不变;同时标记该点已访问,这个点为末尾的前缀出现的次数+当前迭代的层数,然后转移到向下一个点;对KMP的失配函数深入了解一点的话,这个思路也挺好理解的,举个例子,aba....aba....aba 第一次迭代,末尾-->3 3标记掉,层数+1=1,3-->1,标记掉层数+1=2,此时a出现了两次;枚举到中间那个aba的时候,'a'-->3,层数+1=1,发现3访问过了,所以3-->1的时候层数不变还是1,然后a出现的次数+1,如果层数每次都是+1的话,显然第二次3-->1的时候,3位置的a被重复统计了,所以在从被访问过的点转移的时候,迭代的层数是保持不变的。

#include <iostream>#include <cstring>#include <algorithm>#include <cstdio>#include <cmath>using namespace std;typedef long long ll;const int maxn=210000;bool ok[maxn];int f[maxn];char s[maxn],ss[maxn];int cnt[maxn];void getFail(char* P,int* f){    int m=strlen(P);    f[0]=0;    f[1]=0;    for (int i=1; i<m; i++)    {        int j=f[i];        while(j && P[i]!=P[j]) j=f[j];        f[i+1]=P[i]==P[j]?j+1:0;    }}bool find(char* T,char* P,int* f){    int n=strlen(T);    int m=strlen(P);//    getFail(P,f);    int j=0;    for (int i=0; i<n; i++)    {        while(j && P[j]!=T[i]) j=f[j];        if (P[j]==T[i]) j++;        if (j==m) return true;    }    return false;}int tt;int n,m,k;void slove(int pos,int x){    if (!pos) return;    cnt[pos]+=x;    if (!ok[pos]) slove(f[pos],x+1);    else slove(f[pos],x);    ok[pos]=true;}int main(){//    freopen("in.txt","r",stdin);    scanf("%d",&tt);    while(tt--)    {        scanf("%d",&n);        scanf("%s",s);//        for (int i=0; i<n; i++)//        s[i]=ss[n-i-1];//        s[n]='\0';        getFail(s,f);        memset(ok,0,sizeof ok);        memset(cnt,0,sizeof cnt);        for (int i=n; i>=0; i--)        {            if (ok[i]) continue;            int p=i;            if (p && !ok[p])            {                slove(p,0);//                cnt[f[p]]+=1;            }        }        ll ans=0;        for (int i=1; i<=n; i++)        ans+=cnt[i]+1,ans%=10007;        cout<<ans<<endl;//        cout<<cnt[i]+1<<" ";//        cout<<endl;    }    return 0;}


       4552 这题好像和3336一模一样,这种子串+统计的问题几乎全能用后缀自动机(SAM)做,当时学SAM的时候顺道把这题做了,写SAM的话几乎就是个裸题了..统计一下节点出现次数,累加取模就是答案...

#include <iostream>#include <cstdio>#include <memory.h>#include <algorithm>#include <cmath>#include <string>#include <cstring>using namespace std;const int maxn=210000;const int S=26;const int inf=maxn;char str[maxn>>1],s[maxn>>1],st[maxn>>1];int c[maxn];struct node{    node *par,*go[S];    int val,sp;}*root,*tail,que[maxn],*top[maxn];int tot,len;int ans;int wtop[maxn];int l;inline int idx(char c){    return (int)c-'a';}inline void add(int c,int l){    node *p=tail;    node *np=&que[tot++];    np->val=l;    //np->n1=0;    while (p&&p->go[c]==NULL) p->go[c]=np,p=p->par;    if (p==NULL) np->par=root;    else    {        node *q=p->go[c];        if (p->val+1==q->val) np->par=q;        else        {            node *nq=&que[tot++];            *nq=*q;            nq->val=p->val+1;            np->par=q->par=nq;            while (p&&p->go[c]==q) p->go[c]=nq,p=p->par;        }    }    tail=np;}inline void init(){    memset(que,0,sizeof que);    len=1;    tot=0;    memset(wtop,0,sizeof wtop);    ans=0;    root=tail=&que[tot++];}inline void TopS(){    memset(c,0,sizeof c);    for (int i=0; i<tot; i++)    c[que[i].val]++;    for (int i=1; i<=len; i++)        c[i]+=c[i-1];    for (int i=0; i<tot; i++)    {        top[--c[que[i].val]]=&que[i];        wtop[c[que[i].val]]=i;    }}int main(){    //freopen("a.txt","r",stdin);    while (~scanf("%s",str))    {        l=strlen(str);        init();        for (int i=0; i<l; i++)        {            add(idx(str[i]),len++);        }        TopS();        node *p=root;        for (int i=0; i<l; i++)        {            p=p->go[idx(str[i])];            p->sp=1;        }        for (int i=tot-1; i>0; i--)        {            p=top[i];            p->par->sp+=p->sp;            p->par->sp%=256;        }        p=root;          int ans=0;        for (int i=0; i<l; i++)        {            p=p->go[idx(str[i])];            ans+=p->sp;            ans=ans%256;        }        printf("%d\n",ans);    }    return 0;}


0 0
原创粉丝点击