zoukankan      html  css  js  c++  java
  • HDU 6153 A Secret ( KMP&&DP || 拓展KMP )

    题意 : 给出两个字符串,现在需要求一个和sum,考虑第二个字符串的所有后缀,每个后缀对于这个sum的贡献是这个后缀在第一个字符串出现的次数*后缀的长度,最后输出的答案应当是 sum % 1e9+7

    分析 :

    有两种做法,如果会拓展KMP的话可以说这就是一道模板题了,拓展KMP专门就是找最长公共前缀的长度,首先将给出的两个字符串双双反转,用模式串去跟主串跑一遍拓展KMP,得到 extend 数组,然后只要遍历一遍 extend 数组,每一个 extend[i] 表示模式串里面前 extend[i] 个前缀都出现过了,因此贡献应该是 1+2+...+extend[i],是等差数列

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define LL long long
    const int maxn = 1e6 + 10;
    const int  mod = 1e9 + 7;
    int next[maxn], extend[maxn], moL, strL;
    char mo[maxn], S[maxn];
    LL sum[maxn];
    void GetNext()
    {
        next[0] = moL;
        int a, p;
        for (int i = 1, j = -1; i < moL; i++, j--){
            if (j < 0 || i + next[i - a] >= p){
                if (j < 0) p = i, j = 0;
    
                while (p < moL && mo[p] == mo[j]) p++, j++;
    
                next[i] = j;
                a = i;
            } else next[i] = next[i - a];
        }
    }
    
    void GetExtend()
    {
        GetNext();
        int a;
        int p;
        for (int i = 0, j = -1; i < strL; i++, j--){
            if (j < 0 || i + next[i - a] >= p){
                if (j < 0) p = i, j = 0;
    
                while (p < strL && j < moL && S[p] ==  mo[j])
                    p++, j++;
    
                extend[i] = j;
                a = i;
            } else extend[i] = next[i - a];
        }
    }
    
    inline void PrintAns()
    {
        GetExtend();
        LL ans = 0;
        for(int i=0; i<strL; i++){
            if(extend[i]){
                LL tmp = extend[i];
                tmp = (tmp+1)*tmp/2;
                ans = (ans%mod + tmp%mod)%mod;
            }
        }
        printf("%lld
    ", ans);
    }
    int main()
    {
        int nCase;
        scanf("%d", &nCase);
        while(nCase--){
            scanf("%s %s", S, mo);
            strL = strlen(S);
            moL  = strlen(mo);
            std::reverse(S, S+strL);
            std::reverse(mo, mo+moL);
            PrintAns();
        }
        return 0;
    }
    View Code

    而KMP做法就是用到了NEXT数组的性质,在解决这题之前or后可以看看这道非常相似的题 ==> 51Nod 1277

    只要理解了51Nod 1277的kmp+dp解法,这道题直接效仿即可,关于 51Nod 1277 的题解报告点这里 or 百度

    #include<bits/stdc++.h>
    using namespace std;
    const int mod = 1e9 + 7;
    const int maxn = 1e6 + 10;
    int Next[maxn], moL, strL;
    long long d[maxn];
    char mo[maxn], str[maxn];
    inline void GetNext()
    {
        int i = 0, j = -1;
        Next[i] = j;
        while(i < moL){
            while(j!=-1 && mo[j]!=mo[i]) j = Next[j];
            Next[++i] = ++j;
        }
    }
    inline void Kmp()
    {
        memset(d, 0, sizeof(d));
        int i = 0, j = 0;
        while(i < strL){
            while(j!=-1 && mo[j]!=str[i]) j = Next[j];
            i++, j++, d[j]++;
            if(j == moL) j = Next[j];
        }
    }
    inline void PrintAns()
    {
        GetNext(); Kmp();
        long long sum = 0;
        for(int i=moL; i>0; i--){
            d[Next[i]] += d[i];
            sum = (sum + d[i]*i) % mod;
        }
        printf("%I64d
    ", sum);
    }
    int main(void)
    {
        int nCase;
        scanf("%d", &nCase);
        while(nCase--){
            scanf("%s %s", str, mo);
            moL = strlen(mo);
            strL = strlen(str);
            std::reverse(str, str+strL);
            std::reverse(mo , mo+moL);
            PrintAns();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    2015531 网络攻防 Exp1 PC平台逆向破解(5)M
    2017-2018-1 20155331 嵌入式C语言
    20155330 《网络对抗》 Exp9 web安全基础实践
    20155330 《网络对抗》 Exp8 Web基础
    20155330 《网络对抗》 Exp7 网络欺诈防范
    20155330 《网络对抗》 Exp6 信息搜集与漏洞扫描
    20155330 《网络对抗》 Exp5 MSF基础应用
    20155330 《网络攻防》 Exp4 恶意代码分析
    20155330 《网络攻防》 Exp3 免杀原理与实践
    20155330 《网络对抗》 Exp2 后门原理与实践
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/7577306.html
Copyright © 2011-2022 走看看