ASFNU SC Day6

今天是暑期训练 第七 第六天(中间放了一天假)。

学习字符串简单算法,kmp,AC自动机,trie树等。

----算法模板----

KMP:随手打的,不知道能不能过。 

void getnxt(char *W){
    memset(nxt,-1,sizeof nxt);
    int k=-1,wlen=strlen(W);
    for(int q=0;q<wlen;q++){
        while(k!=-1){
            if(W[q]==W[k]) break;
            k=nxt[k];
        }
        nxt[q+1]=++k;
    }
}
int KMP(char *W,char *T){
    int ans=0;
    int wlen=strlen(W),tlen=strlen(T);
    for(int i=0,j=0;i<=tlen;i++,j++){
        if(j==-1) continue;
        if(W[j]!=T[i]||j==wlen){
            ans+=(j==wlen?1:0);
            i--; j=nxt[j]-1;
            continue;
        }
    }
    return ans;
}

 AC自动机,trie树:

//trie树
void add(char *s,int num){
    int len=strlen(s),x=0;
    val[0]='\n';
    for(int pos=0;pos<len;pos++){
        if(!trie[x][s[pos]-'a']){
            trie[x][s[pos]-'a']=++cnt;
            val[cnt]=s[pos];
        }
        x=trie[x][s[pos]-'a'];
    }
    end[x]=num;
    return ;
}
//AC自动机
queue <int> q;
void bfs(){
    q.push(0);
    while(!q.empty()){
        int now=q.front();q.pop();
        for(int i=0;i<=25;i++){
            if(!trie[now][i]) continue;
            if(now==0){
                q.push(trie[now][i]);
                continue;
            }
            int j=fail[now];
            while(!trie[j][i]&&j)
                j=fail[j];
            fail[trie[now][i]]=trie[j][i];
            q.push(trie[now][i]);
        }
    }
    return ;
}
void search(char *s){
    int x=0;
    int len=strlen(s);
    for(int pos=0;pos<=len;pos++){
        int j=x;
        while(j){
            if(j==fail[j]) exit(-1);
            if(end[j]) ans[end[j]]++;
            j=fail[j];
        }
        while(!trie[x][s[pos]-'a']&&x) x=fail[x];
        x=trie[x][s[pos]-'a'];
    }
    return ;
}

-----模拟赛&例题-----

地址:https://cn.vjudge.net/contest/236074

A.POJ 3461

  kmp裸题。

B.POJ 2752

  有两种想法,但做法一样。

  一、看作自己与自己匹配,每次成功匹配的位置即是答案。

    (不必真的跑KMP,只需要递归加入答案即可)

  二、既然是找相同前缀后缀,那么最长的已经算出,第二长的就是最长的最长相同前缀后缀,以此类推。

    (和上一种实现方法相同)

  其实我认为,这两种想法的等价性就是KMP的精华所在。

C.POJ 3080

  枚举第一个串的字串,然后看看它们是不是其它串的字串。

  原来复杂度是O(len^4*n)的,kmp优化后为O(len^3*n+n^2)

D.POJ 2406

  我们发现,如果循环节存在,那么这个串的最长相同前缀后缀必然和原串只差一个循环节长。

  所以跑nxt后判断输出答案即可。

E.HYSBZ 1030

  AC自动机上DP……

  开始写了一个dfs,获得10分。

  后来考虑优化,发现可以用dp[i][j]表示考虑i位,当前在j的方案数。

  接着我们又会发现如果存含可读单词的方案数在AC自动机上不好跑……

  所以存不含可读单词的,AC自动机上转移即可。

  最后用26^M-Σdp[M][i]即可。

F.HDU 2222

  AC自动机裸题。去年居然RE了……

  教训:strlen不仅不能在循环里用,也不能在递归函数里用,要传参下去。

  T了数百次啊……

附代码:

  以后有时间再放吧。

posted @ 2018-07-01 23:14  臼邦庶民  阅读(126)  评论(0编辑  收藏  举报