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\n", 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\n", 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

 

posted @ 2017-09-22 21:48  qwerity  阅读(161)  评论(0编辑  收藏  举报