【CUC集训】kmp+AC自动机题解

  • 制作:邓楚盟
  • 日期:2018年8月28日

A

  • AC自动机模板题,注意是统计包含哪些单词,不是统计总得出现次数
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# define INF 0x3f3f3f3f
# define clr0(x) memset(x,0,sizeof(x))
# define clr1(x) memset(x,INF,sizeof(x))
# define clrf(x) memset(x,-1,sizeof(x))
# define rep(i,a) for(int i = 0;i<(a);i++)
# define repf(i,a,b) for(int i = (a);i<=(b);i++)
# define repu(i,a,b) for(int i = (a);i<(b);i++)
# define repd(i,a,b) for(int i = (a);i>=(b);i--)
# define lowbit x&(-x)
# define W(a) while(a)
# define Sc(x) scanf("%d",&(x))
# define Sd(x) scanf("%I64d",&(x))
# define Lson(x) (x)<<1
# define Rson(x) (x)<<1|1
# define ll long long
# define fuckio ios::sync_with_stdio(false);
# define fuck cout<<"fuck:"<<__LINE__<q;

    struct _node{
        int nxt[26];
        int cnt,fail;
    }node[max_tot];

    void init(){
        size = 1;
        while(!q.empty())q.pop();
        rep(i,max_tot){
            clr0(node[i].nxt);
            node[i].cnt = node[i].fail = 0;
        }
    }

    void ins(char *s){
        int n = strlen(s);
        int now = 0;
        rep(i,n){
            char c = s[i];
            if(!node[now].nxt[c-'a'])node[now].nxt[c-'a'] = size++;
            now = node[now].nxt[c-'a'];
        }
        node[now].cnt++;
    }

    void build(){
        node[0].fail = -1;
        q.push(0);
        W(!q.empty()){
            int u = q.front();
            q.pop();
            rep(i,26){
                if(node[u].nxt[i]){
                    if(u == 0)node[node[u].nxt[i]].fail = 0;
                    else{
                        int v = node[u].fail;
                        W(v!=-1){
                            if(node[v].nxt[i]){
                                node[node[u].nxt[i]].fail = node[v].nxt[i];
                                break;
                            }else{
                                v = node[v].fail;
                            }
                        }
                        if(v == -1)node[node[u].nxt[i]].fail = 0;
                    }
                    q.push(node[u].nxt[i]);
                }
            }
        }
    }

    int Get(int u){
        int res = 0;
        W(u){
            res += node[u].cnt;
            node[u].cnt = 0;
            u = node[u].fail;
        }
        return res;
    }
    int fid(char *s){
        int n = strlen(s);
        int res = 0;
        int now = 0;
        rep(i,n){
            char c = s[i];
            if(node[now].nxt[c-'a']){
                now = node[now].nxt[c - 'a'];
            }else{
                int p = node[now].fail;
                W(p!=-1&&node[p].nxt[c-'a'] == 0)p = node[p].fail;
                if(p == -1)now = 0;
                else now = node[p].nxt[c-'a'];
            }
            if(node[now].cnt){
                res += Get(now);
            }
        }
        return res;
    }

}aho;

char S[maxn];

int main()
{
    int T,N;
    Sc(T);
    W(T--){
        Sc(N);
        aho.init();
        rep(i,N){
            scanf("%s",S);
            aho.ins(S);
        }
        aho.build();
        scanf("%s",S);
        printf("%d\n",aho.fid(S));
    }
return 0;
}

B

  • 典型的利用kmp的next数组求循环节的例题
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# define INF 0x3f3f3f3f
# define clr0(x) memset(x,0,sizeof(x))
# define clr1(x) memset(x,INF,sizeof(x))
# define rep(i,a) for(int i = 0;i<(a);i++)
# define repf(i,a,b) for(int i = (a);i<=(b);i++)
# define repu(i,a,b) for(int i = (a);i<(b);i++)
# define repd(i,a,b) for(int i = (a);i>=(b);i--)
# define lowbit x&(-x)
# define W(a) while(a)
# define Sc(x) scanf("%d",&(x))
# define Lson(x) (x)<<1
# define Rson(x) (x)<<1|1
# define ll long long
# define fuckio ios::sync_with_stdio(false);
# define fuck cout<<"fuck:"<<__LINE__<

C

  • 求一个串最长前缀使得和另一个串的最长后缀匹配
  • 扩展kmp和kmp都能做
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# define INF 0x3f3f3f3f
# define clr0(x) memset(x,0,sizeof(x))
# define clr1(x) memset(x,INF,sizeof(x))
# define rep(i,a) for(int i = 0;i<(a);i++)
# define repf(i,a,b) for(int i = (a);i<=(b);i++)
# define repu(i,a,b) for(int i = (a);i<(b);i++)
# define repd(i,a,b) for(int i = (a);i>=(b);i--)
# define lowbit x&(-x)
# define W(a) while(a)
# define Sc(x) scanf("%d",&(x))
# define Lson(x) (x)<<1
# define Rson(x) (x)<<1|1
# define ll long long
# define fuckio ios::sync_with_stdio(false);
# define fuck cout<<"fuck:"<<__LINE__<an||ans>bn)ans=kmp.nexta[ans];
        if(!ans)printf("0\n");
        else{
            a[ans] = 0;
            printf("%s %d\n",a,ans);
        }
    }
}

D

  • 可以kmp+dp,也可以直接用扩展kmp做
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# define INF 0x3f3f3f3f
# define clr0(x) memset(x,0,sizeof(x))
# define clr1(x) memset(x,INF,sizeof(x))
# define rep(i,a) for(int i = 0;i<(a);i++)
# define repf(i,a,b) for(int i = (a);i<=(b);i++)
# define repu(i,a,b) for(int i = (a);i<(b);i++)
# define repd(i,a,b) for(int i = (a);i>=(b);i--)
# define lowbit x&(-x)
# define ww(a) while(a)
# define sc(x) scanf("%d",&(x))
# define pc(x) printf("%d\n",(x));
# define lson(x) (x)<<1
# define rson(x) (x)<<1|1
# define ll long long
# define fuckio ios::sync_with_stdio(false);
# define fuck cout<<"fuck:"<<__LINE__<

E

  • 最大最小表示法例题,kmp求个循环节,除一下就好
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# define INF 0x3f3f3f3f
# define clr0(x) memset(x,0,sizeof(x))
# define clr1(x) memset(x,INF,sizeof(x))
# define rep(i,a) for(int i = 0;i<(a);i++)
# define repf(i,a,b) for(int i = (a);i<=(b);i++)
# define repu(i,a,b) for(int i = (a);i<(b);i++)
# define repd(i,a,b) for(int i = (a);i>=(b);i--)
# define lowbit x&(-x)
# define ww(a) while(a)
# define sc(x) scanf("%d",&(x))
# define pc(x) printf("%d\n",(x));
# define lson(x) (x)<<1
# define rson(x) (x)<<1|1
# define ll long long
# define fuckio ios::sync_with_stdio(false);
# define fuck cout<<"fuck:"<<__LINE__<= len) break;
        if (str[(i + l) % len] > str[(j + l) % len]) i = i + l + 1;
        else j = j + l + 1;
        if (i == j) j++;
    }
    return i < j ? i : j;
}

int getmax(char *str){
    int i = 0, j = 1, k = 0;
    int len = strlen(str);
    while (i < len && j < len && k < len) {
        int t = str[(i + k) % len] - str[(j + k) % len];
        if (!t) k++;
        else {
            if (t > 0) j = j + k + 1;
            else i = i + k + 1;
            if (i == j) j++;
            k = 0;
        }
    }
    return i < j ? i : j;
}


int n;
char s[maxn];
int main()
{
    fuckio
    ww(scanf("%s",s)!=EOF){
        int len = strlen(s);
        kmp.init();
        kmp.getnext(s);
        int Min = getmin(s);
        int Max = getmax(s);
        int tmp = 0;
        if(len%(len-kmp.nexta[len]) == 0)tmp = len/(len-kmp.nexta[len]);
        else tmp =  1;
        printf("%d %d %d %d\n", Min + 1, tmp, Max + 1, tmp);
    }
}

F

  • 原字符串x2,然后跑扩展kmp,枚举位置查看extnd数组,如果大于等于n说明,相等,否则比较不想等的那个位置的大小关系
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# define INF 0x3f3f3f3f
# define clr0(x) memset(x,0,sizeof(x))
# define clr1(x) memset(x,INF,sizeof(x))
# define rep(i,a) for(int i = 0;i<(a);i++)
# define repf(i,a,b) for(int i = (a);i<=(b);i++)
# define repu(i,a,b) for(int i = (a);i<(b);i++)
# define repd(i,a,b) for(int i = (a);i>=(b);i--)
# define lowbit x&(-x)
# define ww(a) while(a)
# define sc(x) scanf("%d",&(x))
# define pc(x) printf("%d\n",(x));
# define lson(x) (x)<<1
# define rson(x) (x)<<1|1
# define ll long long
# define fuckio ios::sync_with_stdio(false);
# define fuck cout<<"fuck:"<<__LINE__<= p)
            {
                int j = (p-k+1)>0 ? (p-k+1) : 0;
                ww(k+j= p)
            {
                int j= (p-k+1) > 0 ? (p-k+1) : 0;
                while(k+j=lent)ans2++;
            else{
                if(s[i+ekmp.extnd[i]]

G

  • AC自动机板子题,会卡内存,建议使用指针形式写ac自动机(虽然我没有……)
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# define INF 0x3f3f3f3f
# define clr0(x) memset(x,0,sizeof(x))
# define clr1(x) memset(x,INF,sizeof(x))
# define rep(i,a) for(int i = 0;i<(a);i++)
# define repf(i,a,b) for(int i = (a);i<=(b);i++)
# define repu(i,a,b) for(int i = (a);i<(b);i++)
# define repd(i,a,b) for(int i = (a);i>=(b);i--)
# define lowbit x&(-x)
# define ww(a) while(a)
# define sc(x) scanf("%d",&(x))
# define pc(x) printf("%d\n",(x));
# define lson(x) (x)<<1
# define rson(x) (x)<<1|1
# define ll long long
# define fuckio ios::sync_with_stdio(false);
# define fuck cout<<"fuck:"<<__LINE__<v;

struct Aho{

    int size = 1;
    queueq;

    struct _node{
        int nxt[128];
        int cnt,fail,id;
    }node[max_tot];

    void init(){
        size = 1;
        while(!q.empty())q.pop();
        rep(i,max_tot){
            clr0(node[i].nxt);
            node[i].cnt = node[i].fail = node[i].id = 0;
        }
    }

    void ins(char *s,int x){
        int n = strlen(s);
        int now = 0;
        rep(i,n){
            char c = s[i];
            if(!node[now].nxt[c])node[now].nxt[c] = size++;
            now = node[now].nxt[c];
        }
        node[now].cnt++;
        node[now].id = x;
    }

    void build(){
        node[0].fail = -1;
        q.push(0);
        ww(!q.empty()){
            int u = q.front();
            q.pop();
            rep(i,128){
                if(node[u].nxt[i]){
                    if(u == 0)node[node[u].nxt[i]].fail = 0;
                    else{
                        int v = node[u].fail;
                        ww(v!=-1){
                            if(node[v].nxt[i]){
                                node[node[u].nxt[i]].fail = node[v].nxt[i];
                                break;
                            }else{
                                v = node[v].fail;
                            }
                        }
                        if(v == -1)node[node[u].nxt[i]].fail = 0;
                    }
                    q.push(node[u].nxt[i]);
                }
            }
        }
    }

    int fid(char *s){
        int n = strlen(s);
        bool res = false;
        int now = 0;
        rep(i,n){
            char c = s[i];
            if(node[now].nxt[c]){
                now = node[now].nxt[c];
            }else{
                int p = node[now].fail;
                ww(p!=-1&&node[p].nxt[c] == 0)p = node[p].fail;
                if(p == -1)now = 0;
                else now = node[p].nxt[c];
            }
            if(node[now].cnt){
                res = true;
                v.push_back(node[now].id);
            }
        }
        return res;
    }

}aho;

char s[maxn];
int n,m;
int main()
{
    fuckio
    ww(sc(n)!=EOF){
        aho.init();
        v.clear();
        rep(i,n){
            scanf("%s",s);
            aho.ins(s,i+1);
        }
        aho.build();
        sc(m);
        int tot = 0;
        repf(i,1,m){
            v.clear();
            scanf("%s",s);
            if(aho.fid(s)){
                tot ++;
                printf("web %d: ",i);
                sort(v.begin(),v.end());
                rep(i,v.size()-1)printf("%d ",v[i]);
                printf("%d\n",v[v.size()-1]);
            }
        }
        printf("total: %d\n",tot);
    }
return 0;
}

H

  • 板子题
  • 可以把A-Z以外的字符都归为第26号字符,A-Z是0-25
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# include 
# define INF 0x3f3f3f3f
# define clr0(x) memset(x,0,sizeof(x))
# define clr1(x) memset(x,INF,sizeof(x))
# define rep(i,a) for(int i = 0;i<(a);i++)
# define repf(i,a,b) for(int i = (a);i<=(b);i++)
# define repu(i,a,b) for(int i = (a);i<(b);i++)
# define repd(i,a,b) for(int i = (a);i>=(b);i--)
# define lowbit x&(-x)
# define ww(a) while(a)
# define sc(x) scanf("%d",&(x))
# define pc(x) printf("%d\n",(x));
# define lson(x) (x)<<1
# define rson(x) (x)<<1|1
# define ll long long
# define fuckio ios::sync_with_stdio(false);
# define fuck cout<<"fuck:"<<__LINE__<v;
int ans[1020];
struct Aho{

    int size = 1;
    queueq;

    struct _node{
        int nxt[27];
        int cnt,fail,id;
    }node[max_tot];

    void init(){
        size = 1;
        while(!q.empty())q.pop();
        rep(i,max_tot){
            clr0(node[i].nxt);
            //rep(j,27)node[i].nxt[j] = 0;
            node[i].cnt = node[i].fail =node[i].id= 0;
        }
    }

    void ins(char *s,int x){
        int n = strlen(s);
        int now = 0;
        rep(i,n){
            int c = s[i]-'A';
            //if(c<0||c>25)c = 26;
            if(!node[now].nxt[c])node[now].nxt[c] = size++;
            now = node[now].nxt[c];
        }
        node[now].cnt++;
        node[now].id = x;
    }

    void build(){
        node[0].fail = -1;
        q.push(0);
        ww(!q.empty()){
            int u = q.front();
            q.pop();
            rep(i,27){
                if(node[u].nxt[i]){
                    if(u == 0)node[node[u].nxt[i]].fail = 0;
                    else{
                        int v = node[u].fail;
                        ww(v!=-1){
                            if(node[v].nxt[i]){
                                node[node[u].nxt[i]].fail = node[v].nxt[i];
                                break;
                            }else{
                                v = node[v].fail;
                            }
                        }
                        if(v == -1)node[node[u].nxt[i]].fail = 0;
                    }
                    q.push(node[u].nxt[i]);
                }
            }
        }
    }

    int fid(char *s){
        int n = strlen(s);
        int res = 0;
        int now = 0;
        rep(i,n){
            if(s[i]<'A'||s[i]>'Z')s[i]= 'Z'+1;
            int c = s[i]-'A';
            if(node[now].nxt[c]){
                now = node[now].nxt[c];
            }else{
                int p = node[now].fail;
                ww(p!=-1&&node[p].nxt[c] == 0)p = node[p].fail;
                if(p == -1)now = 0;
                else now = node[p].nxt[c];
            }
            if(node[now].cnt){
                res++;
                ans[node[now].id]++;
            }
        }
        return res;
    }

}aho;

char virus[1020][100];
char s[2000020];
int n,m;
int main()
{
    ww(sc(n)!=EOF){
        clr0(ans);
        aho.init();
        repf(i,1,n){
            scanf("%s",virus[i]);
            aho.ins(virus[i],i);
        }
        aho.build();
        scanf("%s",s);
        if(aho.fid(s)){
            repf(i,1,n){
                if(ans[i]){
                    printf("%s: %d\n",virus[i],ans[i]);
                }
            }
        }
    }
return 0;
}

你可能感兴趣的:(【CUC集训】kmp+AC自动机题解)