zoukankan      html  css  js  c++  java
  • bzoj4641 基因改造 KMP / hash

    依稀记得,$NOIP$之前的我是如此的弱小....

    完全不会$KMP$的写法,只会暴力$hash$....

    大体思路为把一个串的哈希值拆成$26$个字母的位权

    即$hash(S) = sumlimits_{a} a * sum w^i * [s[i] == a]$

    通过记录每个字母第一次出现的位置,用$26$的时间来确定$f$是什么

    然后通过确定的$f$计算出$f$是正确的时候的$hash$值,和原串的$hash$值比较

    复杂度$O(26n)$

    自然取模....

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    namespace remoon {
        #define ri register int
        #define ll long long
        #define ull unsigned long long
        #define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
        #define drep(io, ed, st) for(ri io = ed; io >= st; io --)
    }
    using namespace std;
    using namespace remoon;
    
    #define sid 500050
    char s[2005000], t[sid];
    
    int n, m, tim, f[200];
    int num[200], vis[200], nxt[200], tot;
    ull val[200], wei[sid];
    ull seed = 19260817;
    
    inline void Init() {
        wei[0] = 1;
        rep(i, 1, m) wei[i] = wei[i - 1] * seed;
        rep(i, 1, m) {
            int le = t[i];
            if(!vis[le]) nxt[++ tot] = i, vis[le] = 1;
            val[le] += wei[m - i];
        }
        tim ++;
    }
    
    inline void Solve() {
        ull now = 0, tval = 0;
        rep(i, 1, m) now += s[i] * wei[m - i];
        rep(i, m, n) {
            
            tim ++;
            int flag = 0;
    
            rep(j, 1, tot) {
                int v = s[i - m + nxt[j]];
                if(vis[v] == tim) { flag = 1; break; }
                if(vis[v] != tim) vis[v] = tim;      
                f[j] = v;
            }
            
            if(!flag) {
                tval = 0;
                rep(j, 1, tot) 
                tval += f[j] * val[t[nxt[j]]];
                if(tval == now) write(i - m + 1);
            }
            
            now -= s[i - m + 1] * wei[m - 1];
            now *= seed; now += s[i + 1];
        }
    }
    
    int main() {
        scanf("%s", s + 1); n = strlen(s + 1); 
        scanf("%s", t + 1); m = strlen(t + 1);
        Init(); Solve();
        return 0;
    }

    现在我明白了$KMP$是非常伟大的算法....

    对于此题而言,考虑每个字符的上一个字符离当前字符的距离,这可以成为一个新串

    然后比对新串即可

    特别的,如果上一个字符出现的位置超过了匹配长度,那么我们也要视作合法

    但是,我们发现这种匹配满足有前效性,没有后效性,因此可以用$KMP$

    复杂度$O(n)$,十分的优秀

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    namespace remoon {
        #define ri register int
        #define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
        #define drep(io, ed, st) for(ri io = ed; io >= st; io --)
    }
    using namespace std;
    using namespace remoon;
    
    const int sid = 1005000;
    
    int n, m;
    char s[sid], t[sid];
    int lst[200], S[sid], T[sid], nxt[sid];
    
    inline bool match(int x, int y) {
        if(y > m) return 0;
        if(x == T[y]) return 1;
        if(!T[y] && x >= y) return 1;
        return 0;
    }
    
    int main() {
        scanf("%s", s + 1); scanf("%s", t + 1);
        n = strlen(s + 1); m = strlen(t + 1);
        
        rep(i, 1, n) {
            S[i] = lst[s[i]] ? i - lst[s[i]] : 0;
            lst[s[i]] = i;
        }
        
        memset(lst, 0, sizeof(lst));
        rep(i, 1, m) {
            T[i] = lst[t[i]] ? i - lst[t[i]] : 0;
            lst[t[i]] = i;
        }
        
        for(ri i = 2, j = 0; i <= m; i ++) {
            while(j && !match(T[i], j + 1)) j = nxt[j];
            if(match(T[i], j + 1)) j ++; 
            nxt[i] = j;
        }
        
        for(ri i = 1, j = 0; i <= n; i ++) {
            while(j && !match(S[i], j + 1)) j = nxt[j];
            if(match(S[i], j + 1)) j ++;
            if(j == m) printf("%d
    ", i - m + 1);
        }
        return 0;
    }
  • 相关阅读:
    three.js中 用 鼠标点击+呼吸灯
    socket.io学习以及在vuehtml使用,node搭建的后台
    网路在线古诗文免费阅读网站
    vue-element-admin默认加载Dashboard更改
    vue-element-admin后台框架侧边蓝图标添加自定义
    吸顶操作vue
    对图片进行裁剪(vueCropper)图片不显示
    ucharts使用内容
    文字转换为语音在线免费工具连接
    tree.js外部骨骼动画
  • 原文地址:https://www.cnblogs.com/reverymoon/p/9949445.html
Copyright © 2011-2022 走看看