• D. Tavas and Malekas DFS模拟 + kmp + hash || kmp + hash


    http://codeforces.com/contest/535/problem/D

    如果真的要把m个串覆盖上一个串上面,是可以得,不会超时。

    要注意到一点,全部覆盖后再判断时候合法,和边放边判断,结果是一样的,后者还更难做到。

    那么就是先按顺序把串覆盖上去,已经存在的就不去覆盖了,然后kmp一次记录匹配位置,判断即可。

    用DFS覆盖,DFS回溯的时候记录一个数组tonext[i]表示第i个点的第一个空位是tonext[i],这样覆盖上去就是O(n)

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    const int maxn = 1e6 + 20;
    const int MOD = 1e9 + 7;
    int tonext[maxn];
    int ret;
    char str[maxn];
    char sub[maxn];
    void dfs(int cur, int k, int from) {
        if (k < 0) return;
        if (k == 0) {
            ret = cur;
            return;
        }
        if (tonext[cur] != cur) {
            ret = tonext[cur];
            dfs(tonext[cur], k - (tonext[cur] - cur), from + tonext[cur] - cur);
            tonext[cur] = ret;
        } else {
            ret = cur + 1;
            str[cur] = sub[from];
            dfs(cur + 1, k - 1, from + 1);
            tonext[cur] = ret;
        }
    }
    int a[maxn];
    bool HASH[maxn];
    int kmpnext[maxn];
    void get_next(char sub[], int lensub) {
        int i = 1, j = 0;
        kmpnext[1] = 0;
        while (i <= lensub) {
            if (j == 0 || sub[i] == sub[j]) {
                kmpnext[++i] = ++j;
            } else j = kmpnext[j];
        }
        return;
    }
    void kmp(int lenstr, int lensub) {
        int i = 1, j = 1;
        while (i <= lenstr) {
            if (j == 0 || str[i] == sub[j]) {
                ++i;
                ++j;
            } else j = kmpnext[j];
            if (j == lensub + 1) {
                HASH[i - lensub] = true;
                j = kmpnext[j];
            }
        }
        return;
    }
    void work() {
        int lenstr, m;
        scanf("%d%d", &lenstr, &m);
        for (int i = 1; i <= lenstr; ++i) {
            tonext[i] = i;
            str[i] = 'A';
    //        printf("f");
        }
    //    printf("%c
    ", str[1]);
        scanf("%s", sub + 1);
        int lensub = strlen(sub + 1);
        for (int i = 1; i <= m; ++i) {
            scanf("%d", &a[i]);
            dfs(a[i], lensub, 1);
        }
        str[lenstr + 1] = '';
    //    printf("%s
    ", str + 1);
        get_next(sub, lensub);
        kmp(lenstr, lensub);
        for (int i = 1; i <= m; ++i) {
            if (!HASH[a[i]]) {
                cout << 0 << endl;
                return;
            }
        }
        LL ans = 1;
        for (int i = 1; i <= lenstr; ++i) {
            if (str[i] == 'A') {
                ans *= 26;
                if (ans >= MOD) ans %= MOD;
            }
        }
        cout << ans << endl;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
    View Code

    开始的时候想不到直接kmp

    用的其实就是kmp的next数组,不断next[next[]]

    就是记录所有的前缀和后缀相等。

    对于abc****abc,也就是前后缀相等的话,长度是3

    记上一个覆盖到的位置是pos[i - 1] + lensub - 1

    然后如果这个和他没交集,就算,如果有,要判断。怎么判断呢?

    算出交集大小,如果交集刚好是3,那么是可以得。否则,是NO

    交集是3说明后缀的那3个和前缀匹配了。

    注意m可能是0

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    const int maxn = 1e6 + 20;
    const int MOD = 1e9 + 7;
    char sub[maxn];
    int tonext[maxn];
    int pos[maxn];
    bool book[maxn];
    void get_next(char sub[], int lensub) {
        int i = 1, j = 0;
        tonext[1] = 0;
        while (i <= lensub) {
            if (j == 0 || sub[i] == sub[j]) {
                tonext[++i] = ++j;
            } else j = tonext[j];
        }
        return;
    }
    void work() {
        int lenstr, m;
    //    cin >> lenstr >> m;
    //    cin >> sub + 1;
        scanf("%d%d", &lenstr, &m);
        scanf("%s", sub + 1);
        int lensub = strlen(sub + 1);
        get_next(sub, lensub);
        for (int i = 1; i <= m; ++i) {
    //        cin >> pos[i];
            scanf("%d", &pos[i]);
        }
        int t = tonext[lensub + 1];
        while (t != 1) {
            book[t - 1] = true;
            t = tonext[t];
        }
        int total = lenstr - lensub;
        if (m == 0) {
            total += lensub;
        }
        for (int i = 2; i <= m; ++i) {
            int to = pos[i - 1] + lensub - 1;
            int haha = to - pos[i] + 1;
            if (haha <= 0) {
                total -= lensub;
                continue;
            }
            if (!book[haha]) {
                printf("0
    ");
                return;
            }
            total -= lensub - haha;
        }
        LL ans = 1;
        for (int i = 1; i <= total; ++i) {
            ans *= 26;
            if (ans >= MOD) ans %= MOD;
        }
        printf("%I64d
    ", ans);
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
    View Code
  • 相关阅读:
    mac idea 更换主题
    记一次Sonarqube踩坑实录
    Mysql 常用数据类型
    Spring Cloud 整合分布式链路追踪系统Sleuth和ZipKin实战,分析系统瓶颈
    git clone克隆github仓库慢,问题解决
    SpringBoot 解决跨域问题
    Android 中的敏感信息泄露
    Drozer 测试 APP
    Drozer 安装踩坑日记
    安卓测试笔记--工具安装
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6145139.html
Copyright © 2020-2023  润新知